## Using Intermediate Terms in Equations

### Why Use Intermediate Terms?

Textbooks often define certain equation terms in separate equations, and then substitute these intermediate equations into the main one. For example, for fully developed flow in ducts, the Darcy friction factor can be used to compute pressure loss:

`$P=\frac{f·L·\rho ·{V}^{2}}{2D}$`

where `P` is pressure, `f` is the Darcy friction factor, `L` is length, ρ is density, `V` is flow velocity, and `D` is hydraulic area.

These terms are further defined by:

`$f=\frac{0.316}{{\mathrm{Re}}^{1/4}}$`

`$\mathrm{Re}=\frac{D·V}{\nu }$`

`$D=\sqrt{\frac{4A}{\pi }}$`

`$V=\frac{q}{A}$`

where `Re` is the Reynolds number, `A` is the area, `q` is volumetric flow rate, and ν is the kinematic viscosity.

In Simscape™ language, there are two ways that you can define intermediate terms for use in equations:

• `intermediates` section — Declare reusable named intermediate terms in the `intermediates` section in a component or domain file. You can reuse these intermediate terms in any equations section within the same component file, in an enclosing composite component file, or in any component that has nodes of that domain type.

• `let` expressions in the `equations` section — Declare intermediate terms in the declaration clause and use them in the expression clause of the same `let` expression. Use this method if you need to define intermediate terms of limited scope, for use in a single group of equations. This way, the declarations and equations are close together, which improves code readability.

Another advantage of using named intermediate terms instead of `let` expressions is that you can include named intermediate terms in simulation data logs.

The following example shows the same Darcy-Weisbach equation with intermediate terms written out in Simscape language:

```component MyComponent [...] parameters L = { 1, 'm' }; % Length rho = { 1e3, 'kg/m^3' }; % Density nu = { 1e-6, 'm^2/s' }; % Kinematic viscosity end variables p = { 0, 'Pa' }; % Pressure q = { 0, 'm^3/s' }; % Volumetric flow rate A = { 0, 'm^2' }; % Area end intermediates f = 0.316 / Re_d^0.25; % Darcy friction factor Re_d = D_h * V / nu; % Reynolds number D_h = sqrt( 4.0 * A / pi ); % Hydraulic diameter V = q / A; % Flow velocity end equations p == f * L * rho * V^2 / (2 * D_h); % final equation end end end ```

After substitution of all intermediate terms, the final equation becomes:

```p==0.316/(sqrt(4.0 * A / pi) * q / A / nu)^0.25 * L * rho * (q / A)^2 / (2 * sqrt(4.0 * A / pi)); ```

When you use this component in a model and log simulation data, the logs will include data for the four intermediate terms, with their descriptive names (such as ```Darcy friction factor```) shown in the Simscape Results Explorer.

### Declaring and Using Named Intermediate Terms

The `intermediates` section in a component file lets you define named intermediate terms for use in equations. Think of named intermediate terms as of defining an alias for an expression. You can reuse it in any equations section within the same file or an enclosing composite component. When an intermediate term is used in an equation, it is ultimately substituted with the expression that it refers to.

You can also include an `intermediates` section in a domain file and reuse these intermediate terms in any component that has nodes of that domain type.

#### Syntax Rules and Restrictions

You declare an intermediate term by assigning a unique identifier on the left-hand side of the equal sign (`=`) to an expression on the right-hand side of the equal sign.

The expression on the right-hand side of the equal sign:

• Can refer to other intermediate terms. For example, in the Darcy-Weisbach equation, the identifier `Re_d` (Reynolds number) is used in the expression declaring the identifier `f` (Darcy friction factor). The only requirement is that these references are acyclic.

• Can refer to parameters, variables, inputs, outputs, member components and their parameters, variables, inputs, and outputs, as well as Across variables of domains used by the component nodes.

• Cannot refer to Through variables of domains used by the component nodes.

You can use intermediate terms in equations, as described in Use in Equations. However, you cannot access intermediate terms in the `setup` function.

Intermediate terms can appear in simulation data logs and Simscape Results Explorer, as described in Data Logging. However, intermediate terms do not appear in:

• Variable Viewer

• Statistics Viewer

• Operating Point data

• Block dialog boxes and Property Inspector

#### Use in Equations

After declaring an intermediate term, you can refer to it by its identifier anywhere in the equations section of the same component. For example:

```component A [...] parameters p1 = { 1, 'm' }; end variables v1 = { 0, 'm' }; v2 = { 0, 'm^2' }; end intermediates int_expr = v1^2 * pi / p1; end equations v2 == v1^2 + int_expr; end end ```

You can refer to a public intermediate term declared in a member component in the equations of an enclosing composite component. For example:

```component B [...] components comp1 = MyPackage.A; end variables v1 = { 0, 'm^2' }; end [...] equations v1 == comp1.int_expr; end end ```

Similarly, you can refer to an intermediate term declared in a domain in the equations section of any component that has nodes of this domain type. For example:

```domain D [...] intermediates int_expr = v1 / sqrt(2); end [...] end ```
```component C [...] nodes n = D; end variables v1 = { 0, 'V' }; end [...] equations v1 == n.int_expr; end end ```

Accessibility of intermediate terms outside of the file where they are declared is governed by their `Access` attribute value. For mode information, see Attribute Lists.

#### Data Logging

Intermediate terms with `ExternalAccess` attribute values of `modify` or `observe` are included in simulation data logs. For mode information, see Attribute Lists.

If you specify a descriptive name for an intermediate term, this name appears in the status panel of the Simscape Results Explorer.

For example, you declare the intermediate term `D_h` (hydraulic diameter) as a function of the orifice area:

```component E [...] intermediates D_h = sqrt( 4.0 * A / pi ); % Hydraulic diameter end [...] end ```

When you use a block based on this component in a model and log simulation data, selecting `D_h` in the Simscape Results Explorer tree on the left displays a plot of the values of the hydraulic diameter over time in the right pane and the name ```Hydraulic diameter``` in the status panel at the bottom. For more information, see About the Simscape Results Explorer.

### Using the `let` Expressions

`let` expressions provide another way to define intermediate terms for use in one or more equations. Use this method if you need to define intermediate terms of limited scope, for use in a single group of equations. This way, the declarations and equations are close together, which improves file readability.

The following example shows the same Darcy-Weisbach equation as in the beginning of this topic but with intermediate terms written out using the `let` expression:

```component MyComponent [...] parameters L = { 1, 'm' }; % Length rho = { 1e3, 'kg/m^3' }; % Density nu = { 1e-6, 'm^2/s' }; % Kinematic viscosity end variables p = { 0, 'Pa' }; % Pressure q = { 0, 'm^3/s' }; % Volumetric flow rate A = { 0, 'm^2' }; % Area end equations let f = 0.316 / Re_d^0.25; % Darcy friction factor Re_d = D_h * V / nu; % Reynolds number D_h = sqrt( 4.0 * A / pi ); % Hydraulic diameter V = q / A; % Flow velocity in p == f * L * rho * V^2 / (2 * D_h); % final equation end end end ```

After substitution of all intermediate terms, the final equation becomes:

```p==0.316/(sqrt(4.0 * A / pi) * q / A / nu)^0.25 * L * rho * (q / A)^2 / (2 * sqrt(4.0 * A / pi)); ```

However, in this case the four intermediate terms do not appear in logged simulation data.

#### Syntax Rules of `let` Expressions

A `let` expression consists of two clauses, the declaration clause and the expression clause.

```equations [...] let declaration clause in expression clause end [...] end ```

The declaration clause assigns an identifier, or set of identifiers, on the left-hand side of the equal sign (`=`) to an equation expression on the right-hand side of the equal sign:

``` LetValue = EquationExpression ```

The expression clause defines the scope of the substitution. It starts with the keyword `in`, and may contain one or more equation expressions. All the expressions assigned to the identifiers in the declaration clause are substituted into the equations in the expression clause during parsing.

Note

The `end` keyword is required at the end of a `let-in-end` statement.

Here is a simple example:

```component MyComponent [...] variables x = 0; y = 0; end equations let z = y + 1; in x == z; end end end ```

In this example, the declaration clause of the `let` expression sets the value of the identifier `z` to be the expression `y` + 1. Thus, substituting `y` + 1 for `z` in the expression clause in the `let` statement, the code above is equivalent to:

```component MyComponent [...] variables x = 0; y = 0; end equations x == y + 1; end end end ```

There may be multiple declarations in the declaration clause. These declarations are order independent. The identifiers declared in one declaration may be referred to by the expressions for identifiers in other declarations in the same declaration clause. Thus, in the example with the Darcy-Weisbach equation, the identifier `Re_d` (Reynolds number) is used in the expression declaring the identifier `f` (Darcy friction factor). The only requirement is that the expression references are acyclic.

The expression clause of a `let` expression defines the scope of the substitution for the declaration clause. Other equations, that do not require these substitutions, may appear in the equation section outside of the expression clause. In the following example, the equation section contains the equation expression ```c == b + 2``` outside the scope of the `let` expression before it.

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations let x = a + 1; in b == x; end c == b + 2; end end ```

These expressions are treated as peers. They are order independent, so this example is equivalent to

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations c == b + 2; let x = a + 1; in b == x; end end end ```

and, after the substitution, to

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations b == a + 1; c == b + 2; end end ```

#### Nested `let` Expressions

You can nest `let` expressions, for example:

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations let w = a + 1; in let z = w + 1; in b == z; c == w; end end end end ```

In case of nesting, substitutions are performed based on both of the declaration clauses. After the substitutions, the code above becomes:

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations b == a + 1 + 1; c == a + 1; end end ```

The innermost declarations take precedence. The following example illustrates a nested `let` expression where the inner declaration clause overrides the value declared in the outer one:

```component MyComponent [...] variables a = 0; b = 0; end equations let w = a + 1; in let w = a + 2; in b == w; end end end end ```

Performing substitution on this example yields:

``` component MyComponent [...] variables a = 0; b = 0; end equations b == a + 2; end end ```

#### Conditional `let` Expressions

You can use `if` statements within both declarative and expression clause of `let` expressions, for example:

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations let x = if a < 0, a else b end; in c == x; end end end ```

Here `x` is declared as the conditional expression based on `a < 0`. Performing substitution on this example yields:

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations c == if a < 0, a else b end; end end ```

The next example illustrates how you can use `let` expressions within conditional expressions. The two `let` expressions on either side of the conditional expression are independent:

```component MyComponent [...] variables a = 0; b = 0; c = 0; end equations if a < 0 let z = b + 1; in c == z; end else let z = b + 2; in c == z; end end end end ```

This code is equivalent to:

``` component MyComponent [...] variables a = 0; b = 0; c = 0; end equations if a < 0 c == b + 1; else c == b + 2; end end end ```

#### Identifier List in the Declarative Clause

This example shows using an identifier list, rather than a single identifier, in the declarative clause of a `let` expression:

```component MyComponent [...] variables a = 0; b = 0; c = 0; d = 0; end equations let [x, y] = if a < 0, a; -a else -b; b end; in c == x; d == y; end end end ```

Here `x` and `y` are declared as the conditional expression based on `a < 0`. Notice that each side of the `if` statement defines a list of two expressions. A first semantic translation of this example separates the `if` statement into

```if a < 0, a; -a else -b; b end => { if a < 0, a else -b end; if a < 0, -a else b end }```

then the second semantic translation becomes

```[x, y] = { if a < 0, a else -b end; if a < 0, -a else b end } => x = if a < 0, a else -b end; y = if a < 0, -a else b end;```

and the final substitution on this example yields:

```component MyComponent [...] variables a = 0; b = 0; c = 0; d = 0; end equations c == if a < 0, a else -b end; d == if a < 0, -a else b end; end end ```