Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
calculate_functors [2026/07/03 03:21]
hermann
calculate_functors [2026/07/23 03:55] (current)
hermann
Line 13: Line 13:
 | [[Calculate Lookup Table Values]] | ''​%''​ | Lookup table (values computed) | Once per row of a base lookup table | | [[Calculate Lookup Table Values]] | ''​%''​ | Lookup table (values computed) | Once per row of a base lookup table |
 | [[Calculate Lookup Table Keys And Values]] | <​nowiki>​%%</​nowiki>​ | Lookup table (keys and values computed) | Once per row — two separate expressions | | [[Calculate Lookup Table Keys And Values]] | <​nowiki>​%%</​nowiki>​ | Lookup table (keys and values computed) | Once per row — two separate expressions |
 +
 +The shorthand symbols are also referred to as **abbreviated syntax** — both terms mean the same thing and are used interchangeably in this documentation and in the Dinamica EGO GUI options.
  
 The expression language, including all arithmetic, logical, conditional,​ spatial, and stochastic operators, is described in full in [[#​the_expression_language|The Expression Language]] section. Per-functor restrictions and the availability of each operator category are noted both in each functor'​s own section and in the relevant expression-language subsections. For a complete description of the EGO Script syntax used to call these functors — including the shorthand symbols, hook blocks, and conversion between forms — see [[ego_script#​calculator_functor_shorthand|Calculator functor shorthand]] in the EGO Script documentation. The expression language, including all arithmetic, logical, conditional,​ spatial, and stochastic operators, is described in full in [[#​the_expression_language|The Expression Language]] section. Per-functor restrictions and the availability of each operator category are noted both in each functor'​s own section and in the relevant expression-language subsections. For a complete description of the EGO Script syntax used to call these functors — including the shorthand symbols, hook blocks, and conversion between forms — see [[ego_script#​calculator_functor_shorthand|Calculator functor shorthand]] in the EGO Script documentation.
Line 33: Line 35:
 | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. |
 | Result Is Sparse | Boolean Value Type | No | False | If ''​True'',​ only non-null cells are stored — saves memory but slows random access. | | Result Is Sparse | Boolean Value Type | No | False | If ''​True'',​ only non-null cells are stored — saves memory but slows random access. |
-| Result Format | Map Type | No | None | Optional reference map whose spatial format (extent, resolution, projection) is applied to the output. Category information in the reference map is ignored. |+| Result Format | Map Type | No | None | Optional reference map whose spatial format (extent, resolution, projection) is applied to the output. Category information in the reference map is ignored. Prefer this port over a ''​NumberMap''​ hook when the map is needed only for format purposes — a hook defines an identifier in the expression namespace and blocks abbreviated syntax if that identifier is unused in the expression. |
  
 ==== Output ==== ==== Output ====
Line 59: Line 61:
 | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. | | Null Value | Null Value Type | No | Based on Cell Type | Sentinel value representing "no data" in the output. |
 | Result Is Sparse | Boolean Value Type | No | False | If ''​True'',​ only non-null cells are stored. | | Result Is Sparse | Boolean Value Type | No | False | If ''​True'',​ only non-null cells are stored. |
-| Result Format | Map Type | No | None | Optional reference map whose spatial format is applied to the output. |+| Result Format | Map Type | No | None | Optional reference map whose spatial format is applied to the output. Prefer this port over a ''​NumberMap''​ hook when the map is needed only for format purposes — a hook defines an identifier in the expression namespace and blocks abbreviated syntax if that identifier is unused in the expression. |
  
 ==== Output ==== ==== Output ====
Line 108: Line 110:
 | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. |
 | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. |
-| Base Lookup Table | Lookup Table Type | No | ''​.none''​ | A lookup table whose key set drives iteration. When ''​.none'',​ the lowest-indexed connected ​''​NumberTable''​ (verbose form) or the first lookup table named in the expression (shorthand form) is used instead ​— not a union of all connected tables. |+| Base Lookup Table | Lookup Table Type | No | ''​.none''​ | A lookup table whose key set drives iteration. When ''​.none'',​ the ''​NumberTable'' ​hook with the lowest list index that is connected to a **lookup table** (not a regular table) is used as the row source ​(verbose form)or the first lookup table named in the expression (shorthand form) — not a union of all connected tables. Prefer this port over a ''​NumberTable''​ hook when the table is needed only to define the row set and is not referenced in the expression, to keep abbreviated syntax available. |
  
 ==== Output ==== ==== Output ====
Line 138: Line 140:
 | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. | | Key Column Name | String | **Yes** | — | Name of the key column in the output lookup table. |
 | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. | | Value Column Name | String | **Yes** | — | Name of the value column in the output lookup table. |
-| Base Lookup Table | Lookup Table Type | No | ''​.none''​ | A lookup table whose row set drives iteration. |+| Base Lookup Table | Lookup Table Type | No | ''​.none''​ | A lookup table whose row set drives iteration. Prefer this port over a ''​NumberTable''​ hook when the table is needed only to define the row set and is not referenced in the expression, to keep abbreviated syntax available. |
  
 ==== Output ==== ==== Output ====
Line 203: Line 205:
 | 6 | **Divide** | ''​EXPR / EXPR''​ |   | ''​i1 / i2''​ | | 6 | **Divide** | ''​EXPR / EXPR''​ |   | ''​i1 / i2''​ |
 | 6 | **Modulo** | ''​EXPR % EXPR''​ | Remainder after integer division | ''​i1 % 100''​ | | 6 | **Modulo** | ''​EXPR % EXPR''​ | Remainder after integer division | ''​i1 % 100''​ |
-| 7 | **Power** | ''​EXPR ^ EXPR''​ | Exponentiation | ''​i1 ^ 3''​ | +| 7 | **Power** | ''​EXPR ​<​nowiki>​^</​nowiki> ​EXPR''​ | Exponentiation | ''​i1 ​<​nowiki>​^</​nowiki> ​3''​ | 
-| 8 | **Catch Error (''?''​)** | ''​EXPR ? EXPR''​ | If the left expression produces an algebraic error (division by zero, key not found, etc.), return the right expression instead. | ''​(i1 / i2) ? (i1 - i2)''​ |+| 8 | **Catch Error (''?''​)** | ''​EXPR ? EXPR''​ | If the left expression produces an algebraic error (division by zero, key not found, etc.), ​evaluate and return the **fallback ​expression** instead. The fallback can be any expression, including another calculation,​ a conditional,​ or a nested ''?''​. | ''​(i1 / i2) ? (i1 - i2)''​ |
 | 9 | **Boolean Not** | ''​not EXPR''​ / ''​! EXPR''​ | Inverts a boolean value. | ''​not isNull(i1)''​ | | 9 | **Boolean Not** | ''​not EXPR''​ / ''​! EXPR''​ | Inverts a boolean value. | ''​not isNull(i1)''​ |
 | 9 | **Negate** | ''​-EXPR''​ | Arithmetic negation. | ''​-ceil(i1 + i2)''​ | | 9 | **Negate** | ''​-EXPR''​ | Arithmetic negation. | ''​-ceil(i1 + i2)''​ |
- 
-> **Note on null and equality:** Writing ''​i1 == null''​ does **not** test for null — because null participates in no arithmetic comparison, it always produces null itself, poisoning the expression. Always use ''​isNull(i1)''​ instead. See the [[#​null_value_handling|Null Value Handling]] section for full details. 
  
 ---- ----
Line 226: Line 226:
 | Asin | ''​asin(EXPR)''​ | Arcsine; output in radians | ''​asin(i1 + i2)''​ | | Asin | ''​asin(EXPR)''​ | Arcsine; output in radians | ''​asin(i1 + i2)''​ |
 | Atan | ''​atan(EXPR)''​ | Arctangent; output in radians | ''​atan(i1 + i2)''​ | | Atan | ''​atan(EXPR)''​ | Arctangent; output in radians | ''​atan(i1 + i2)''​ |
-| Exp | ''​exp(EXPR)''​ | Natural exponential (e^x) | ''​exp(i1 + i2)''​ |+| Exp | ''​exp(EXPR)''​ | Natural exponential (e<​nowiki>​^</​nowiki>​x) | ''​exp(i1 + i2)''​ |
 | Natural Logarithm | ''​ln(EXPR)''​ | log base e | ''​ln(i1 / i4)''​ | | Natural Logarithm | ''​ln(EXPR)''​ | log base e | ''​ln(i1 / i4)''​ |
 | Log base 10 | ''​log(EXPR)''​ |   | ''​log(i1 / i4)''​ | | Log base 10 | ''​log(EXPR)''​ |   | ''​log(i1 / i4)''​ |
Line 239: Line 239:
  
 ===== Clamping Functions ===== ===== Clamping Functions =====
 +
 +All clamping functions are available in all five calculator functors.
  
 ^ Function ^ Syntax ^ Description ^ Example ^ ^ Function ^ Syntax ^ Description ^ Example ^
Line 246: Line 248:
 ===== Random / Stochastic Functions ===== ===== Random / Stochastic Functions =====
  
-These functions generate a new random sample **for each evaluation unit** each time the expression is evaluated. In [[Calculate Map]] and [[Calculate Categorical Map]], this means one sample per cell, making them suitable for spatially stochastic models. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], one sample is drawn per table row. In [[Calculate Value]], a single sample is drawn for the whole expression.+All stochastic ​functions ​are available in all five calculator functors. They generate a new random sample **for each evaluation unit** each time the expression is evaluated. In [[Calculate Map]] and [[Calculate Categorical Map]], this means one sample per cell, making them suitable for spatially stochastic models. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], one sample is drawn per table row. In [[Calculate Value]], a single sample is drawn for the whole expression.
  
 ^ Function ^ Syntax ^ Description ^ Example ^ ^ Function ^ Syntax ^ Description ^ Example ^
Line 257: Line 259:
  
 ^ Function ^ Syntax ^ Description ^ Example ^ ^ Function ^ Syntax ^ Description ^ Example ^
-| Literal value | ''​2'',​ ''​-3.5e-2'',​ etc. | Any numeric literal, including scientific notation. | ''​2 + i1 / -3.5e-2''​ | +| Literal value | ''​2'',​ ''​-3.5e-2'',​ etc. | Any numeric literal, including scientific notation. Available in all five calculator functors. | ''​2 + i1 / -3.5e-2''​ | 
-| Abort | ''​abort''​ | Immediately halts model execution. Useful as a guard inside a conditional to catch unexpected states. | ''​if i1 > 0 then i1 * i2 + 4 else abort''​ |+| Abort | ''​abort''​ | Immediately halts model execution. Useful as a guard inside a conditional to catch unexpected states. Available in all five calculator functors. | ''​if i1 > 0 then i1 * i2 + 4 else abort''​ | 
 +| Is Null | ''​isNull(EXPR)''​ | Returns 1 if the expression is null, 0 otherwise. Immune to the null poisoning rule — always resolves to 0 or 1. Available in all five calculator functors. | ''​if not isNull(i1) then i1 else i2''​ | 
 +| Null | ''​null''​ | Makes the current evaluation unit null — the cell, row, or scalar result is marked as missing and any further arithmetic using it propagates null. This is an **abstract** null, not a numeric value; it cannot be used in arithmetic and has no numeric representation. Available in all five calculator functors. | ''​if i1 > 2 then i1 else null''​ | 
 + 
 +> **Note on null and equality:** Writing ''​i1 == null''​ does **not** test for null — because null participates in no arithmetic comparison, it always produces null itself, poisoning the expression. Always use ''​isNull(i1)''​ instead. See the [[#​null_value_handling|Null Value Handling]] section for full details.
  
 ---- ----
Line 279: Line 285:
 ^ Operator ^ Syntax ^ Description ^ Example ^ ^ Operator ^ Syntax ^ Description ^ Example ^
 | Get Image Value | ''​iX''​ | Returns the value of image X at the **current cell**. | ''​i2''​ | | Get Image Value | ''​iX''​ | Returns the value of image X at the **current cell**. | ''​i2''​ |
-| Get Image Value At Location | ''​iX[LINE_EXPR,​ COL_EXPR]''​ | Returns the value of image X at the **specified (line, column) coordinate**. If the target cell is null, **returns 0** (not null). | ''​i1[line - 1, column - 2]''​ | +| Get Image Value At Location | ''​iX[LINE_EXPR,​ COL_EXPR]''​ | Returns the value of image X at the **specified (line, column) coordinate**. Coordinates outside the image boundary are **mirrored** back into range. For a row coordinate ''​cellLine''​ in an image of N rows, ''​cellLine''​ is normally expected to be in the range [1, N]. When ''​cellLine''​ is outside this range, it is mirrored back: if ''​cellLine''​ ≤ 0, the effective row is ''​1 − cellLine''​ (for instance, ''​cellLine''​ = 0 → row 1, ''​cellLine''​ = −1 → row 2, ''​cellLine''​ = −2 → row 3); if ''​cellLine''​ > N, the effective row is ''​2N + 1 − cellLine''​ (for instance, ''​cellLine''​ = N+1 → row N, ''​cellLine''​ = N+2 → row N−1, ''​cellLine''​ = N+3 → row N−2). The same formula applies independently to the column coordinate ''​cellCol''​. If the target cell is null, **returns 0** (not null). | ''​i1[line - 1, column - 2]''​ | 
-| Get Image Null Value | ''​null''​ | Returns the null sentinel value for the current output ​image, ​making ​the current cell nullUsing ''​null''​ in arithmetic ​always poisons the result. | ''​if i1 > 2 then i1 else null''​ | +| Get Image Null Sentinel ​Value | ''​null(iX)''​ | Returns the **numeric ​sentinel value** stored in image X to represent missing data (e.g. −132767, or any other number defined when the image was created)Unlike the abstract ​''​null'' ​keyword, this is a real number that participates normally ​in arithmetic ​— but be aware that using it as if it were a regular data value may produce misleading results. | ''​if null(i2) > 2 then 1 else null''​ |
-| Get Image Null Value (specific) | ''​null(iX)''​ | Returns the null sentinel ​value defined for image X specifically. | ''​if null(i2) > 2 then 1 else null''​ | +
-| Is Null | ''​isNull(EXPR)''​ | Returns 1 if the expression result is null, 0 otherwise. The **correct** way to test for null. | ''​if not isNull(i1) then i1 else i2''​ |+
 | Get Line Number | ''​line''​ | In map calculators:​ returns the **row index** of the current cell, **counting from 1**. In lookup table calculators:​ returns the **key of the current row**. | ''​line + 1''​ | | Get Line Number | ''​line''​ | In map calculators:​ returns the **row index** of the current cell, **counting from 1**. In lookup table calculators:​ returns the **key of the current row**. | ''​line + 1''​ |
 | Get Column Number | ''​column''​ | In map calculators:​ returns the **column index** of the current cell being processed, **counting from 1**. In lookup table calculators:​ returns the **value associated with the key of the current row** in the base lookup table. | ''​if column / 2 > 50 then 1 else null''​ | | Get Column Number | ''​column''​ | In map calculators:​ returns the **column index** of the current cell being processed, **counting from 1**. In lookup table calculators:​ returns the **value associated with the key of the current row** in the base lookup table. | ''​if column / 2 > 50 then 1 else null''​ |
Line 310: Line 314:
 | Key existence test | ''​tX[?​ EXPR]''​ / ''​tX[=?​ EXPR]''​ / ''​tX[==?​ EXPR]''​ | Returns **1** if EXPR matches a key in the table, **0** otherwise. Does not retrieve a value. | ''​t2[?​ i2]''​ | | Key existence test | ''​tX[?​ EXPR]''​ / ''​tX[=?​ EXPR]''​ / ''​tX[==?​ EXPR]''​ | Returns **1** if EXPR matches a key in the table, **0** otherwise. Does not retrieve a value. | ''​t2[?​ i2]''​ |
 | Named attribute | ''​tX["​NAME"​]''​ | Returns the value bound to a **predefined attribute name** (e.g. ''"​cellArea"''​). Only valid for tables produced by [[Extract Map Attributes]] or [[Extract Lookup Table Attributes]]. | ''​t2["​cellArea"​]''​ | | Named attribute | ''​tX["​NAME"​]''​ | Returns the value bound to a **predefined attribute name** (e.g. ''"​cellArea"''​). Only valid for tables produced by [[Extract Map Attributes]] or [[Extract Lookup Table Attributes]]. | ''​t2["​cellArea"​]''​ |
 +
 +> **Note:** The syntax ''​tX{EXPR}''​ (curly braces) was a deprecated alias for ''​tX[<​= EXPR]''​ and is no longer supported.
  
 The bound operators (''<​='',​ ''<'',​ ''>​='',​ ''>'',​ ''><'',​ ''/''​) are especially useful for **range-based reclassification** and **interpolation**,​ where your table defines breakpoints rather than exact class codes. The bound operators (''<​='',​ ''<'',​ ''>​='',​ ''>'',​ ''><'',​ ''/''​) are especially useful for **range-based reclassification** and **interpolation**,​ where your table defines breakpoints rather than exact class codes.
Line 326: Line 332:
 | Default column | ''​tX[ [EXPR, EXPR, ...] ]''​ | Returns the value in the **first data column** matching the given set of keys. | ''​t2[ [i1 + 2, i2/2, t1[v2]] ]''​ | | Default column | ''​tX[ [EXPR, EXPR, ...] ]''​ | Returns the value in the **first data column** matching the given set of keys. | ''​t2[ [i1 + 2, i2/2, t1[v2]] ]''​ |
 | Named column | ''​tX[ [EXPR, EXPR, ...] ["​COL_NAME"​] ]''​ | Returns the value in the **named data column** matching the given set of keys. | ''​t2[ [i1 + 2, i2/2, t1[v2]] ["​Area_In_Hectares"​] ]''​ | | Named column | ''​tX[ [EXPR, EXPR, ...] ["​COL_NAME"​] ]''​ | Returns the value in the **named data column** matching the given set of keys. | ''​t2[ [i1 + 2, i2/2, t1[v2]] ["​Area_In_Hectares"​] ]''​ |
-| Indexed column | ''​tX[ [EXPR, EXPR, ...] [EXPR] ]''​ | Returns the value in the **column indexed by the second expression** matching the given set of keys. | ''​t2[ [i1 + 2, i2/2, t1[v2]] [v1+2] ]''​ |+| Indexed column | ''​tX[ [EXPR, EXPR, ...] [EXPR] ]''​ | Returns the value in the **column indexed by the second expression** matching the given set of keys. Column indices are **1-based**. | ''​t2[ [i1 + 2, i2/2, t1[v2]] [v1+2] ]''​ |
  
 These operators allow joining spatial data to rich tabular datasets at the cell level — for example, retrieving a transition probability from a multi-dimensional probability table keyed by land-use class and elevation zone. These operators allow joining spatial data to rich tabular datasets at the cell level — for example, retrieving a transition probability from a multi-dimensional probability table keyed by land-use class and elevation zone.
Line 349: Line 355:
 | ''​x''​ | Column coordinate to anchor the window centre (optional) | | ''​x''​ | Column coordinate to anchor the window centre (optional) |
  
-The window centre defaults to the current cell when ''​y''​ and ''​x''​ are omitted. For even-sized windows, the centre is displaced toward the top-left corner. **Null cells within the window are excluded from all calculations.**+The window centre defaults to the current cell when ''​y''​ and ''​x''​ are omitted. For even-sized windows, the centre is displaced toward the top-left corner. When any cell in the window falls outside the image boundary, its coordinate is resolved using the same mirror formula as ''​iX[LINE,​ COL]'',​ applied **independently to each out-of-bounds cell**: for a row coordinate ''​cellLine''​ in an image of N rows, if ''​cellLine''​ ≤ 0 the effective row is ''​1 − cellLine'',​ and if ''​cellLine''​ > N the effective row is ''​2N + 1 − cellLine'';​ the same applies to column coordinates. This applies to every cell in the window — not just the anchor position — so a window near the edge of the image will sample mirrored cells for all positions that extend beyond the boundary. **Null cells within the window are excluded from all calculations.**
  
 ^ Operator ^ Syntax ^ Description ^ Example ^ ^ Operator ^ Syntax ^ Description ^ Example ^
Line 360: Line 366:
 | Median | ''​nbMedian(...)''​ | Median of non-null cells. For an even count, the **greater** of the two central values is returned. | ''​nbMedian(i1,​ 5, 5)''​ | | Median | ''​nbMedian(...)''​ | Median of non-null cells. For an even count, the **greater** of the two central values is returned. | ''​nbMedian(i1,​ 5, 5)''​ |
 | Mode | ''​nbMode(...)''​ | Most frequent value among non-null cells. Returns null if no mode exists; returns the **lesser** value if multiple modes tie. | ''​nbMode(i1,​ 5, 5)''​ | | Mode | ''​nbMode(...)''​ | Most frequent value among non-null cells. Returns null if no mode exists; returns the **lesser** value if multiple modes tie. | ''​nbMode(i1,​ 5, 5)''​ |
-| Variance | ''​nbVar(...)''​ | Population variance of non-null cells: sum of (xi - mean)^2 / n | ''​nbVar(i4,​ 7, 7) / 25''​ |+| Variance | ''​nbVar(...)''​ | Population variance of non-null cells: sum of (xi - mean)<​nowiki>​^</​nowiki>​2 / n | ''​nbVar(i4,​ 7, 7) / 25''​ |
 | Standard Deviation | ''​nbStdDev(...)''​ | Population standard deviation of non-null cells: sqrt of variance | ''​nbStdDev(i2,​ 3, 3, line+1, column)''​ | | Standard Deviation | ''​nbStdDev(...)''​ | Population standard deviation of non-null cells: sqrt of variance | ''​nbStdDev(i2,​ 3, 3, line+1, column)''​ |
  
Line 369: Line 375:
 > **Availability:​** [[Calculate Map]] and [[Calculate Categorical Map]] only. > **Availability:​** [[Calculate Map]] and [[Calculate Categorical Map]] only.
  
-These operators compute a neighbourhood statistic and then use the result as an **index** to retrieve a value from either a lookup table or a second image.+These operators compute a neighbourhood statistic and then use the result as an **index** to retrieve a value from either a connected Lookup Table or a second image. ''​TABLE''​ below always refers to a **Lookup Table** specifically — see section 5 for the operators that query one directly. 
 + 
 +> If ''​TABLE''​ is bound to a multi-column Table (not a Lookup Table), an error is reported. See section 6 for multi-column tables.
  
 **Full syntax:** \\ **Full syntax:** \\
Line 379: Line 387:
 ''​nbN(IMAGE,​ h, w, IMAGE2)''​ ''​nbN(IMAGE,​ h, w, IMAGE2)''​
  
-When a **TABLE** is provided: the statistic is used as a key to query the lookup table. \\+When a **TABLE** ​(Lookup Table) ​is provided: the statistic is used as a key to query it, equivalent to ''​TABLE[statistic]''​ from section 5. \\
 When an **IMAGE2** is provided: the statistic is used as a pixel coordinate to sample ''​IMAGE2''​. When an **IMAGE2** is provided: the statistic is used as a pixel coordinate to sample ''​IMAGE2''​.
  
 ^ Operator ^ Syntax ^ Description ^ Example ^ ^ Operator ^ Syntax ^ Description ^ Example ^
-| MinRef | ''​nbMinRef(...)''​ | Finds the minimum in the window, then uses it as an index. | ''​nbMinRef(i4,​ 2, 3, t1, line, column)''​ | +| MinRef | ''​nbMinRef(...)''​ | Finds the minimum in the window, then uses it as an index into the Lookup Table (or a coordinate into IMAGE2). | ''​nbMinRef(i4,​ 2, 3, t1, line, column)''​ | 
-| MaxRef | ''​nbMaxRef(...)''​ | Finds the maximum in the window, then uses it as an index. | ''​nbMaxRef(i4,​ 2, 3, i1, line, column)''​ |+| MaxRef | ''​nbMaxRef(...)''​ | Finds the maximum in the window, then uses it as an index into the Lookup Table (or a coordinate into IMAGE2). | ''​nbMaxRef(i4,​ 2, 3, i1, line, column)''​ |
  
 ---- ----
Line 395: Line 403:
  
 **Syntax:** ''​nbConvol(IMAGE,​ TABLE, h, w)''​ / ''​nbConvol(IMAGE,​ TABLE, h, w, y, x)''​ **Syntax:** ''​nbConvol(IMAGE,​ TABLE, h, w)''​ / ''​nbConvol(IMAGE,​ TABLE, h, w, y, x)''​
 +
 +> If ''​TABLE''​ is bound to a multi-column Table (not a Lookup Table), an error is reported. See section 6 for multi-column tables.
  
 ^ Parameter ^ Meaning ^ ^ Parameter ^ Meaning ^
 | ''​IMAGE''​ | The image to convolve (''​iX''​) | | ''​IMAGE''​ | The image to convolve (''​iX''​) |
-| ''​TABLE''​ | A Table whose entries are the kernel coefficients,​ indexed 1 to h*w, mapped **left-to-right,​ top-to-bottom** |+| ''​TABLE''​ | A **Lookup ​Table** whose entries are the kernel coefficients,​ indexed 1 to h*w, mapped **left-to-right,​ top-to-bottom**|
 | ''​h''​ | Number of kernel rows | | ''​h''​ | Number of kernel rows |
 | ''​w''​ | Number of kernel columns | | ''​w''​ | Number of kernel columns |
 | ''​y'',​ ''​x''​ | Anchor position (optional; defaults to window centre) | | ''​y'',​ ''​x''​ | Anchor position (optional; defaults to window centre) |
  
-**Kernel index mapping for 3x3 kernel (h=3w=3):**+Each cell in the window is assigned ​unique integer key, starting at 1 and advancing left-to-right,​ then top-to-bottom. The ''​TABLE''​ argument must be a Lookup Table containing one row per window cell, where the key is that cell's index and the value is its convolution coefficient. The result of ''​nbConvol''​ is the weighted sum of all pixel values in the windoweach multiplied by the coefficient stored at the corresponding key in the table.
  
-Table key Window position ​+The grids below illustrate the index mapping for some common window sizes: 
-| 1 | top-left ​| + 
-| 2 | top-centre ​| +**3×3 window (h=3, w=3):** 
-| 3 | top-right ​+ 
-| 4 | mid-left ​+  col 1  ^  col 2  ^  col 3  ​
-centre ​+^ row 1    ​2  ​ ​3  ​| 
-mid-right ​+^ row 2 |  ​4  ​ ​5  ​ ​6 ​ | 
-bottom-left ​+^ row 3 |  ​7 ​ |  8  |  9  ​
-bottom-centre ​+ 
-| 9 | bottom-right ​|+**5×5 window (h=5, w=5):** 
 + 
 +^  ^  col 1  ^  col 2  ^  col 3  ^  col 4  ^  col 5  ^ 
 +^ row 1  ​1 ​ |  2  |  3  |  ​  ​5  ​
 +^ row 2  ​6  ​ ​7 ​ |  8  |  9  |  10  ​
 +^ row 3  ​11  ​ ​12 ​ |  13  |  14  |  15  ​
 +^ row 4  ​16  ​ ​17 ​ |  18  |  19  |  20  ​
 +^ row 5  ​21  ​ ​22 ​ |  23  |  24  |  25  | 
 + 
 +**3×5 window (h=3, w=5) — non-square example:​** 
 + 
 +^  ^  col 1  ^  col 2  ^  col 3  ^  col 4  ^  col 5  ^ 
 +^ row 1 |  1  |  2  |  3  |  4  |  5  ​
 +^ row 2  ​6 ​ |  7  |  8  |  ​  ​10  ​| 
 +^ row 3 |  11  |  12  |  13  |  14  |  15  | 
 + 
 +In all cases the total number of keys required in the table is h × w.
  
 **Example:​** Apply a Gaussian-blur kernel stored in ''​t1''​ over a 3x3 window on ''​i1'':​ **Example:​** Apply a Gaussian-blur kernel stored in ''​t1''​ over a 3x3 window on ''​i1'':​
Line 425: Line 451:
 ====== Null Value Handling ====== ====== Null Value Handling ======
  
-Null values ​**propagate by default**. Any null input in any operand — whether ​map cell (''​iX''​), a table or lookup-table lookup ​(''​tX[...]''​), ​or a scalar ​value (''​vX''​) ​— produces ​null result, unless ​the null is explicitly caught. This behaviour is identical across all five calculator functors and across every operand type.+===== General rule (all five functors) ===== 
 + 
 +A null value in any operand ​**poisons the entire expression**: the result becomes ​null regardless of what the rest of the expression does. This is not special case — it is the default behaviour for every operator and every operand type, across all five calculator functors. 
 + 
 +> **Note:** The keyword ​''​null''​ (available in all five functors) is an **abstract** sentinel — it carries no numeric value and cannot participate in arithmetic. It is distinct from ''​null(iX)'' ​(available in map calculators only), which returns the **numeric** ​value that image X uses internally to mark missing cells. These two are not interchangeable: ​''​null'' ​poisons any expression that uses it; ''​null(iX)''​ is regular number that happens to be the image'​s no-data sentinel.
  
 ^ Expression ^ Null behaviour ^ ^ Expression ^ Null behaviour ^
Line 431: Line 461:
 | ''​v1 / 0''​ | Always null — division by zero is null regardless of operand type | | ''​v1 / 0''​ | Always null — division by zero is null regardless of operand type |
 | ''​t1[v1]''​ | Null if the key ''​v1''​ is not found in lookup table ''​t1''​ | | ''​t1[v1]''​ | Null if the key ''​v1''​ is not found in lookup table ''​t1''​ |
-| ''​i1 + t1[line] / v1 ^ 3''​ | Null if the map cell ''​i1'',​ the table lookup ''​t1[line]'',​ or the value ''​v1''​ is null |+| ''​i1 + t1[line] / v1 <​nowiki>​^</​nowiki> ​3''​ | Null if the map cell ''​i1'',​ the table lookup ''​t1[line]'',​ or the value ''​v1''​ is null |
 | ''​if isNull(t1[v1]) then 1 else 2''​ | **Never null** — ''​isNull''​ itself always resolves to 0 or 1 | | ''​if isNull(t1[v1]) then 1 else 2''​ | **Never null** — ''​isNull''​ itself always resolves to 0 or 1 |
 | ''​if isNull(v1) then i2 else t1[line]''​ | May be null, depending on ''​i2''​ or the table lookup ''​t1[line]''​ | | ''​if isNull(v1) then i2 else t1[line]''​ | May be null, depending on ''​i2''​ or the table lookup ''​t1[line]''​ |
Line 437: Line 467:
 | ''​(t1[v1]) ? i1''​ | If the key ''​v1''​ is not found in ''​t1'',​ falls back to ''​i1'';​ may still be null if ''​i1''​ is null | | ''​(t1[v1]) ? i1''​ | If the key ''​v1''​ is not found in ''​t1'',​ falls back to ''​i1'';​ may still be null if ''​i1''​ is null |
  
-**Two safe patterns for handling nulls — shown here against a table lookup and a scalar value, but equally ​applicable to map cells:**+The poison spreads through the entire chain: if ''​i1''​ is null, then ''​i1 + 5''​ is null, ''​(i1 + 5) * v1''​ is null, and so on. There is no way to "​un-null"​ a result once a null has entered the calculation — except by explicitly testing for it first. 
 + 
 +In a realistic expression, null can enter from several independent sources simultaneously. This expression computes a weighted transition probability from two input maps and a per-class calibration table: 
 + 
 +<​code>​ 
 +(i1 * t1[i3] + i2 * (1 - t1[i3])) / v1 
 +</​code>​ 
 + 
 +Here ''​i1''​ is a distance map, ''​i2''​ a slope map, ''​i3''​ a land-use class map, ''​t1''​ a calibration table keyed by class code, and ''​v1''​ a normalisation scalar. The result is null if //any// of the following is true at the current cell: ''​i1'',​ ''​i2'',​ or ''​i3''​ is null; the class code in ''​i3''​ is not a key in ''​t1'';​ or ''​v1''​ is zero. A single missing class in the calibration table silently nulls every cell of that class, which may be difficult to diagnose. The defensive form makes each failure mode explicit: 
 + 
 +<​code>​ 
 +if isNull(i1) or isNull(i2) or isNull(i3) then null 
 +else (i1 * (t1[i3] ? 0) + i2 * (1 - (t1[i3] ? 0))) / v1 
 +</​code>​ 
 + 
 +The ''?''​ operator provides a fallback of 0 for any missing table key, so cells whose class is absent from the calibration table are treated as having zero weight rather than propagating null. 
 + 
 +**Two safe patterns for handling nulls — applicable to map cells, table lookups, and scalar values alike:**
  
   - ''​isNull(EXPR)''​ — test for null and branch:   - ''​isNull(EXPR)''​ — test for null and branch:
Line 449: Line 496:
 </​code>​ </​code>​
  
-> ''​iX[LINE, COL]''​ is the one exception: **accessing a map at a specific coordinate ​returns 0 (not null)** when the target cell is null. This exception applies ​only to map coordinate lookups — a table or lookup-table key lookup (''​tX[EXPR]''​) that finds no matching key still returns ​null, as noted in section 5.+**Note:​** ​''​isNull()''​ is immune to the poisoning rule — it always ​returns 0 or 1, never null, even when its argument ​is null. It is the only reliable way to branch on null.
  
-If the computed real value exceeds the range of the chosen Cell Type, that cell is also written as null rather than wrapping or clipping. ​(This range check applies to the map calculators only, since the other calculator functors ​do not write to a typed cell grid.)+If the computed real value exceeds the range of the chosen Cell Type, that cell is also written as null rather than wrapping or clipping. This range check applies to [[Calculate Map]] and [[Calculate Categorical Map]] only — the only two functors that accept a Cell Type parameter and write to a typed cell grid. 
 + 
 +===== Exceptions in map calculators ​===== 
 + 
 +> **Availability:​** [[Calculate Map]] and [[Calculate Categorical Map]] only. The two exceptions below involve ''​iX''​ references and neighbourhood functionswhich do not exist in the other three calculator functors
 + 
 +  * **Coordinate lookup** ''​iX[LINE_EXPR,​ COL_EXPR]''​ — accessing a map at a specific coordinate returns **0**, ​not null, when the target cell **is null**. Coordinates that fall **outside the image boundary** are mirrored back into range rather than producing an error. For a row coordinate ''​cellLine''​ in an image of N rows, ''​cellLine''​ is normally expected ​to be in the range [1, N]. When ''​cellLine''​ is outside this range, it is mirrored back: if ''​cellLine''​ ≤ 0, the effective row is ''​1 − cellLine''​ (for instance, ''​cellLine''​ = 0 → row 1, ''​cellLine''​ = −1 → row 2, ''​cellLine''​ = −2 → row 3); if ''​cellLine''​ > N, the effective row is ''​2N + 1 − cellLine''​ (for instance, ''​cellLine''​ = N+1 → row N, ''​cellLine''​ = N+2 → row N−1, ''​cellLine''​ = N+3 → row N−2). The same formula applies independently to the column coordinate ''​cellCol''​. It can be source of subtle bugs: an expression that tests ''​i1[line-1,​ column] > 0''​ will silently treat a null neighbour as zero rather than nullA table or lookup-table key lookup (''​tX[EXPR]''​that finds no matching key still returns null as normal — this exception applies only to map coordinate lookups. 
 +  * **Neighbourhood functions** ''​nbN(iX,​ h, w)''​ — operators such as ''​nbSum'',​ ''​nbAverage'',​ ''​nbMax'',​ and so on aggregate over a window of cells and **exclude null cells from the calculation**. If ''​i1''​ is null at the current cell, the neighbourhood function simply ignores it and aggregates the remaining non-null cells in the window.
  
 ---- ----
Line 816: Line 870:
   - **Connect your inputs first.** Connect all required tables ([[Number Table]]) and scalars ([[Number Value]]) to the operator'​s ports before opening the editor.   - **Connect your inputs first.** Connect all required tables ([[Number Table]]) and scalars ([[Number Value]]) to the operator'​s ports before opening the editor.
   - **Set the Key Column Name and Value Column Name** for the output lookup table.   - **Set the Key Column Name and Value Column Name** for the output lookup table.
-  - **Connect a Base Lookup Table**, or leave it as ''​.none'',​ in which case the row set instead comes from a single connected table — the lowest-indexed ​''​NumberTable''​ in verbose form, or the first lookup table referenced by name in the expression in shorthand form.+  - **Connect a Base Lookup Table**, or leave it as ''​.none'',​ in which case the row source is the ''​NumberTable'' ​hook with the lowest list index that is connected to a lookup table (not a regular table) ​in verbose form, or the first lookup table referenced by name in the expression in shorthand form.
   - **Open the expression editor.** All connected identifiers appear with their aliases at the top. [[Calculate Lookup Table Values]] has a single expression; [[Calculate Lookup Table Keys And Values]] has separate key and value expressions.   - **Open the expression editor.** All connected identifiers appear with their aliases at the top. [[Calculate Lookup Table Values]] has a single expression; [[Calculate Lookup Table Keys And Values]] has separate key and value expressions.
   - **Write the expression(s)**,​ using ''​line''​ for the current row's key and ''​column''​ for the current row's existing value where needed.   - **Write the expression(s)**,​ using ''​line''​ for the current row's key and ''​column''​ for the current row's existing value where needed.
Line 827: Line 881:
   * **''​line''​ and ''​column''​ are context-dependent.** In [[Calculate Map]] and [[Calculate Categorical Map]], ''​line''​ is the spatial row index and ''​column''​ is the spatial column index of the current pixel, both **starting at 1**. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], both are still available but take on row-oriented meanings: ''​line''​ is the key of the current table row, and ''​column''​ is the value already associated with that key in the base lookup table. A different table'​s value for that same key can be retrieved with ''​%someTable[line]''​. See [[#​4_image_operators_and_functions|section 4]] for full details.   * **''​line''​ and ''​column''​ are context-dependent.** In [[Calculate Map]] and [[Calculate Categorical Map]], ''​line''​ is the spatial row index and ''​column''​ is the spatial column index of the current pixel, both **starting at 1**. In [[Calculate Lookup Table Values]] and [[Calculate Lookup Table Keys And Values]], both are still available but take on row-oriented meanings: ''​line''​ is the key of the current table row, and ''​column''​ is the value already associated with that key in the base lookup table. A different table'​s value for that same key can be retrieved with ''​%someTable[line]''​. See [[#​4_image_operators_and_functions|section 4]] for full details.
   * **Native compilation.** Expression calculations across all five calculator functors can be compiled to native code automatically (requires the optional native expression support package), delivering near-C performance — no user action is needed beyond installing the package.   * **Native compilation.** Expression calculations across all five calculator functors can be compiled to native code automatically (requires the optional native expression support package), delivering near-C performance — no user action is needed beyond installing the package.
-  * **Overflow produces null.** If the result exceeds the Cell Type's range, the cell becomes null rather than wrapping. Applies to the map calculators ​only (the other functors ​return values or table entries that are not constrained to cell type in the same way).+  * **Overflow produces null.** If the result exceeds the Cell Type's range, the cell becomes null rather than wrapping. Applies to [[Calculate Map]] and [[Calculate Categorical Map]] only — the only two functors ​with Cell Type parameter.
   * **Neighbourhood functions ignore nulls.** All ''​nbN''​ operators ([[#​7_image_neighborhood_functions|section 7]]) skip null cells in their window; only non-null cells contribute to the statistic.   * **Neighbourhood functions ignore nulls.** All ''​nbN''​ operators ([[#​7_image_neighborhood_functions|section 7]]) skip null cells in their window; only non-null cells contribute to the statistic.
-  * **''​iX[LINE,​ COL]''​ returns 0, not null, for out-of-bounds ​or null cells.** This is the one exception to the general null-propagation rule. See [[#​4_image_operators_and_functions|section 4]] and [[#​null_value_handling|Null Value Handling]].+  * **''​iX[LINE,​ COL]''​ returns 0, not null, when the target cell is null.** Coordinates outside the image boundary are mirrored rather than treated as out-of-bounds. This is the one exception to the general null-propagation rule. See [[#​4_image_operators_and_functions|section 4]] and [[#​null_value_handling|Null Value Handling]].
  
 ---- ----
Line 841: Line 895:
 | Calculate Lookup Table Values | ''​CalculateLookupTableValues''​ | | Calculate Lookup Table Values | ''​CalculateLookupTableValues''​ |
 | Calculate Lookup Table Keys and Values | ''​CalculateLookupTableKeysAndValues''​ | | Calculate Lookup Table Keys and Values | ''​CalculateLookupTableKeysAndValues''​ |
- 
-