Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
working_with_subregions [2026/08/02 20:46] hermann |
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 there. This 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 parameters, not 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 out, covered 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 = _ } := | ||
| Patcher regionalLandscape regionalProbabilities regionChanges regionParams; | Patcher regionalLandscape regionalProbabilities regionChanges regionParams; | ||
| - | RegionalCategoricalMap "changed_landscape" regionalChanged; | + | RegionalMap "cost_map" regionalChanged; |
| }}; | }}; | ||
| </code> | </code> | ||
| + | |||
| + | [[Patcher]] returns three outputs, and this example only stores one of them. ''corrodedProbabilities'' — the probability surface with used-up areas depleted — and ''remainingChanges'' — a Change Matrix of whatever couldn't be placed, given the current ''neighborWindowLines''/''neighborWindowColumns''/''pruneFactor'' — are both genuinely useful diagnostics in a real model, not values to ignore on principle. They're discarded here only because this page is illustrating region-manager mechanics rather than full Patcher diagnostics. All three outputs are still named explicitly, with the unwanted two bound to ''_'', rather than left out of the destructuring entirely — whether EGO Script allows binding only some of a multi-output functor's outputs isn't confirmed, so naming all of them is the safer pattern used consistently throughout this page. | ||
| + | |||
| + | 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 170: | 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 197: | 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 232: | 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> | ||