Differences

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

Link to this comparison view

Both sides previous revision Previous revision
working_with_subregions [2026/08/02 20:50]
hermann [Collecting regional results]
working_with_subregions [2026/08/02 21:25] (current)
hermann
Line 7: Line 7:
   * **The computation itself requires region-specific inputs.** [[Patcher]] and [[Expander]] each take exactly one [[Transition Matrix Type|Transition Matrix]] and one [[Transition Function Parameter Matrix Type|Transition Function Parameter Matrix]] per call. If those rates or patch parameters genuinely differ by region, there'​s no single call that can express that — running once per region, with region-specific parameters, is the only way to get that behavior.   * **The computation itself requires region-specific inputs.** [[Patcher]] and [[Expander]] each take exactly one [[Transition Matrix Type|Transition Matrix]] and one [[Transition Function Parameter Matrix Type|Transition Function Parameter Matrix]] per call. If those rates or patch parameters genuinely differ by region, there'​s no single call that can express that — running once per region, with region-specific parameters, is the only way to get that behavior.
   * **The map is too large to process as one raster.** Splitting into regions keeps each piece a manageable size to work with, independent of whether the calculation itself cares about regions at all.   * **The map is too large to process as one raster.** Splitting into regions keeps each piece a manageable size to work with, independent of whether the calculation itself cares about regions at all.
-  * **A windowed or accumulating calculation would be distorted at a hard-clipped edge.** Anything that looks beyond the current cell — a cost surface, a distance calculation,​ a neighborhood statistic — needs context past a region'​s boundary ​to avoid treating the edge as if the world stopped thereThis is what ''​borderCells'' ​is for.+  * **A windowed or accumulating calculation would be distorted at a hard-clipped edge.** Anything that looks beyond the current cell — a cost surface, a distance calculation,​ a neighborhood statistic — needs *real* ​context past a region'​s boundary, not just reserved space for it. ''​borderCells'' ​reserves that extra space around each region, but by default it's filled with null, not real data — getting real values into it also requires ''​keepNonRegionCells:​ Yes''​ on the [[Regionalize Map]] / [[Regionalize Categorical Map]] call that produces the regional map.
  
 The first case is structural: some functors simply can't vary their parameters by region any other way. The second and third are about how a computation is carried out, not what it computes — the same result could, in principle, come from one call over the whole map, if size or edge effects weren'​t a concern. The first case is structural: some functors simply can't vary their parameters by region any other way. The second and third are about how a computation is carried out, not what it computes — the same result could, in principle, come from one call over the whole map, if size or edge effects weren'​t a concern.
Line 22: Line 22:
 | ''​regionManager''​ | Internal Output | Region Manager | — | The region manager, exposed to functors nested inside the container. | | ''​regionManager''​ | Internal Output | Region Manager | — | The region manager, exposed to functors nested inside the container. |
  
-A nonzero ''​borderCells''​ matters here too: [[Patcher]]'​s own neighborhood search window (3×3 cells by default) means a region'​s edge cells still need context beyond the hard-clipped boundary, ​even though the main reason this example uses regions at all is the per-region transition parametersnot edge effects.+A nonzero ''​borderCells''​ matters here too: [[Patcher]]'​s own neighborhood search window (3×3 cells by default) means a region'​s edge cells still need real context beyond the hard-clipped boundary. ''​borderCells''​ alone only reserves that space, though ​— making it real data instead of null also requires ''​keepNonRegionCells:​ Yes''​ when the region ​is split outcovered in [[#​splitting_a_global_map_into_regions|Splitting a global map into regions]] below.
  
 **Example** — the shell everything else in this page builds on: **Example** — the shell everything else in this page builds on:
Line 103: Line 103:
 | ''​regionalMap''​ | Output | Map / Categorical Map | — | The map cut down to this region. | | ''​regionalMap''​ | Output | Map / Categorical Map | — | The map cut down to this region. |
  
-[[Patcher]] needs both the landscape and the spatial probability map at matching, region-sized extents:+[[Patcher]] needs both the landscape and the spatial probability map at matching, region-sized extents. Its neighborhood search window means the border cells reserved by ''​borderCells''​ need to hold real data, not null — so ''​keepNonRegionCells''​ is set explicitly to ''​Yes''​ on both calls, rather than left at its default:
  
 <​code>​ <​code>​
 Region regionId {{ Region regionId {{
-    regionalLandscape := RegionalizeCategoricalMap landscapeMap;​ +    regionalLandscape := RegionalizeCategoricalMap ​{ globalMap = landscapeMap, keepNonRegionCells = .yes }
-    regionalProbabilities := RegionalizeMap probabilitiesMap;​+    regionalProbabilities := RegionalizeMap ​{ globalMap = probabilitiesMap, keepNonRegionCells = .yes };
 }}; }};
 </​code>​ </​code>​
Line 137: Line 137:
 ^ Port ^ Direction ^ Type ^ Required? ^ Description ^ ^ Port ^ Direction ^ Type ^ Required? ^ Description ^
 | ''​globalMapName''​ | Input | Name | Yes | The shared name this regional fragment will be collected under. | | ''​globalMapName''​ | Input | Name | Yes | The shared name this regional fragment will be collected under. |
-| ''​regionalMap''​ | Input | Map ([[Regional Map]]) / Categorical Map ([[Regional Categorical Map]]) | Yes | The per-region ​result to store. |+| ''​regionalMap''​ | Input | Map ([[Regional Map]]) / Categorical Map ([[Regional Categorical Map]]) | Yes | The result to store — any map, at any extent, not necessarily already clipped to the region. It's clipped down to the corresponding region automatically. |
 | ''​regionId''​ | Input | Integer Value | No, auto-bound | Which region this fragment belongs to. | | ''​regionId''​ | Input | Integer Value | No, auto-bound | Which region this fragment belongs to. |
 | ''​regionManager''​ | Input | Region Manager | No, auto-bound | The region manager this fragment belongs to. | | ''​regionManager''​ | Input | Region Manager | No, auto-bound | The region manager this fragment belongs to. |
 +
 +That last point is worth being explicit about: the map passed in doesn'​t have to already be region-sized — even the full global map would work, since [[Regional Map]]/​[[Regional Categorical Map]] clip it to the region internally rather than assuming it's already been through [[Regionalize Map]]/​[[Regionalize Categorical Map]]. The worked example below still runs its map through [[Regionalize Map]]/​[[Regionalize Categorical Map]] first, but for a different reason: [[Patcher]] itself needs region-sized inputs to compute against, not just to store the result — the clipping done here is redundant on an already region-sized map, not required by [[Regional Map]] itself.
  
 <​code>​ <​code>​
Line 146: Line 148:
  
 Region regionId {{ Region regionId {{
-    regionalLandscape := RegionalizeCategoricalMap landscapeMap;​ +    regionalLandscape := RegionalizeCategoricalMap ​{ globalMap = landscapeMap, keepNonRegionCells = .yes }
-    regionalProbabilities := RegionalizeMap probabilitiesMap;​+    regionalProbabilities := RegionalizeMap ​{ globalMap = probabilitiesMap, keepNonRegionCells = .yes };
  
     { changedLandscape = regionalChanged,​ corrodedProbabilities = _, remainingChanges = _ } :=     { changedLandscape = regionalChanged,​ corrodedProbabilities = _, remainingChanges = _ } :=
Line 159: Line 161:
  
 A model that does care about ''​remainingChanges''​ would most likely want it accumulated across regions too, the same way [[#​computing_per-class_areas_within_each_region|the area-by-region example]] accumulates its table with [[Mux Table]] — checking, once the loop finishes, whether any region failed to place all of its requested changes. A model that does care about ''​remainingChanges''​ would most likely want it accumulated across regions too, the same way [[#​computing_per-class_areas_within_each_region|the area-by-region example]] accumulates its table with [[Mux Table]] — checking, once the loop finishes, whether any region failed to place all of its requested changes.
 +
 ===== Merging regions back into one map ===== ===== Merging regions back into one map =====
  
Line 173: Line 176:
 A few more things worth knowing before relying on the merge: A few more things worth knowing before relying on the merge:
  
 +  * **Splitting keeps border cells so Patcher'​s neighborhood window has real context; merging discards them anyway.** Each region'​s own border zone duplicates territory another region already owns and computes for itself. Merging with ''​mergeNonRegionCells:​ Yes''​ would pull that duplicated, independently-computed data back in instead of leaving each region'​s own interior result as the authority for its own cells — which is why the worked example uses ''​keepNonRegionCells:​ Yes''​ when splitting, but leaves ''​mergeNonRegionCells''​ at its default ''​No''​.
   * **The merged map's format is inherited from the first fragment stored, not negotiated across all of them.** Cell type, null value, and categorization all come from whichever [[Regional Map]] or [[Regional Categorical Map]] call registered first for that name — only the dimensions come from the regions map itself. If regions are processed in an order that isn't guaranteed, don't rely on which fragment "​wins."​   * **The merged map's format is inherited from the first fragment stored, not negotiated across all of them.** Cell type, null value, and categorization all come from whichever [[Regional Map]] or [[Regional Categorical Map]] call registered first for that name — only the dimensions come from the regions map itself. If regions are processed in an order that isn't guaranteed, don't rely on which fragment "​wins."​
   * **Mismatched null values fail the merge, not silently overwrite each other.** When ''​mergeNonRegionCells''​ brings overlapping border cells from two different regions together, they can only combine if they agree, or one of them is null — two regions disagreeing on what a cell's value should be raises an error rather than picking one.   * **Mismatched null values fail the merge, not silently overwrite each other.** When ''​mergeNonRegionCells''​ brings overlapping border cells from two different regions together, they can only combine if they agree, or one of them is null — two regions disagreeing on what a cell's value should be raises an error rather than picking one.
Line 200: Line 204:
  
         Region regionId {{         Region regionId {{
-            regionalLandscape := RegionalizeCategoricalMap landscapeMap;​ +            regionalLandscape := RegionalizeCategoricalMap ​{ globalMap = landscapeMap, keepNonRegionCells = .yes }
-            regionalProbabilities := RegionalizeMap probabilitiesMap;​+            regionalProbabilities := RegionalizeMap ​{ globalMap = probabilitiesMap, keepNonRegionCells = .yes };
  
             { changedLandscape = regionalChanged,​ corrodedProbabilities = _, remainingChanges = _ } :=             { changedLandscape = regionalChanged,​ corrodedProbabilities = _, remainingChanges = _ } :=
Line 235: Line 239:
 | ''​table''​ | Output | Table | — | The accumulated value entering the current iteration. | | ''​table''​ | Output | Table | — | The accumulated value entering the current iteration. |
  
-This section doesn'​t use [[Region]] at all — ''​regionId''​ is used directly, since [[Regionalize Categorical Map]] and [[Set Table By Key]] both auto-bind or accept it positionally without needing it re-exposed under a container of its own:+This section doesn'​t use [[Region]] at all — ''​regionId''​ is used directly, since [[Regionalize Categorical Map]] and [[Set Table By Key]] both auto-bind or accept it positionally without needing it re-exposed under a container of its own. There'​s also no windowed calculation here, so unlike the [[Patcher]] example, ''​keepNonRegionCells''​ is left at its default — [[Calc Areas]] only tallies cells within the region itself:
  
 <​code>​ <​code>​