femic.patchworks_runtime Module

The femic.patchworks_runtime module is FEMIC’s Patchworks launch and runtime-preparation seam. It takes an already exported Patchworks package and handles the operational work needed to run Matrix Builder or related helper commands: load runtime config, validate host prerequisites, choose the correct launcher mode, capture logs/manifests, and prepare the 1:1 stand/block dataset used by the model runtime.

If you are debugging why Patchworks preflight fails, why Matrix Builder will not launch on Windows or under Wine, or why the runtime package produced the wrong tracks/blocks side effects, this is the first module to read. In practice it owns:

  • Patchworks runtime config loading and validation

  • host-mode detection for native Windows versus Wine/Linux execution

  • preflight checks for Java, Wine, licensing, and exported input artifacts

  • command construction, launch, and manifest/log capture

  • block/topology preparation from exported fragments shapefiles

Start Here If…

Use this page first if you are trying to:

  • understand the boundary between Patchworks export synthesis and actual runtime execution

  • debug patchworks preflight, patchworks matrix-build, or patchworks build-blocks

  • inspect why FEMIC chose native Windows Java versus Wine launch mode

  • trace where stdout/stderr/manifests are written for runtime launches

  • understand what runtime config fields are required before Matrix Builder can run

Typical maintenance path:

  1. Start with load_patchworks_runtime_config() if the issue begins with a runtime YAML/JSON config file.

  2. Move to run_patchworks_preflight() if the problem is about missing Java, Wine, patchworks.jar, license values, or runtime inputs.

  3. Read run_patchworks_command() or run_patchworks_beanshell_script() if the failure happens during command launch or manifest capture.

  4. Read build_patchworks_blocks_dataset() if the problem is in blocks.shp / topology generation rather than Matrix Builder launch.

Typical Usage

The common operator-facing path is:

femic patchworks preflight --instance-root external/femic-k3z-instance --config config/patchworks.runtime.windows.yaml
femic patchworks build-blocks --instance-root external/femic-k3z-instance --config config/patchworks.runtime.windows.yaml
femic patchworks matrix-build --instance-root external/femic-k3z-instance --config config/patchworks.runtime.windows.yaml --run-id k3z_docs_example

At the Python level, maintainers usually call preflight before launch:

from pathlib import Path
from femic.patchworks_runtime import load_patchworks_runtime_config, run_patchworks_preflight

config = load_patchworks_runtime_config(Path("config/patchworks.runtime.windows.yaml"))
result = run_patchworks_preflight(config)

On native Windows, FEMIC can also supervise noninteractive Matrix Builder runs and close the spawned Matrix Builder GUI window automatically once fresh output activity has stabilized. On hosts like the current FEMIC dev environment, the same supervised cleanup also tears down the matching Patchworks launcher cmd.exe shell tree when it lingers after the Java process is done. This behavior is controlled through the runtime config surface:

  • matrix_builder.auto_close_window_on_success

  • matrix_builder.auto_close_settle_seconds

  • matrix_builder.auto_close_timeout_seconds

This automation is intended for the local rebuild workflow and does not replace manifest/log review when something looks wrong.

Critical Headless Scheduling Insight

The current proving-ground no-GUI Patchworks seam has one especially important runtime rule:

  • in the headless BeanShell path, let ca.spatial.patchworks.Control.waitForIterations() own scheduler startup

  • do not call control.resume() immediately before that wait

Live proving-ground smokes showed that the explicit pre-resume() path was the source of the earlier java.lang.IllegalStateException: Not suspended failure. Once that call was removed, the K3Z proving-ground helper could:

  1. reach PatchWorks_Init completion,

  2. wait one unattended iteration,

  3. suspend after the wait,

  4. call saveStage(...), and

  5. return control with a success manifest and saved stage directory.

FEMIC now supervises these Windows headless runs directly:

  • success and failure are detected from explicit trace/log markers

  • failed runs are killed automatically instead of leaving dead shells behind

  • successful runs are also torn down automatically after the success marker and saved-stage verification

First Real Headless Scenario Smoke

The proving-ground seam is now beyond a passive saveStage(...) proof. FEMIC supports a minimal headless scenario mode, max-even-flow-smoke, that activates one target before the bounded wait/save cycle. The first fully useful proving-ground smoke on analysis/intensive_light_standstructure.pin showed that:

  1. product.Yield.managed.Total can be activated headlessly with a modest annual minimum,

  2. the saved scenario/targetStatus.csv records that target as active,

  3. the saved scenario/targetSummary.csv contains non-zero managed-yield currents and derived flow.even.product.Yield.managed.Total values, and

  4. the saved scenario/schedule.csv is non-empty and contains real managed treatments.

One important nuance from the proving-ground evidence:

  • directly activating flow.even.product.Yield.managed.Total changed target state and objective values but still left the saved schedule empty;

  • activating the underlying product.Yield.managed.Total target produced the first useful no-GUI scheduling smoke.

How This Fits Into The Pipeline

This module sits after femic.fmg.patchworks. The export layer writes the package content. This runtime layer decides whether that package is runnable on the current host and then launches the proprietary runtime tools.

At a high level, the owning sequence is:

  1. load and validate runtime config

  2. verify host/runtime prerequisites with preflight

  3. build and launch the correct command for the current host mode

  4. capture stdout/stderr/manifests and detect fatal runtime signatures

  5. optionally prepare blocks.shp and topology CSV inputs expected by the model runtime

That means this module is the operational boundary, not the content-synthesis boundary. If forestmodel.xml or fragments semantics are already wrong, the bug usually belongs in femic.fmg.patchworks. If the package is correct but runtime tooling still fails, this module is the likely owner.

Key Entry Surfaces

The highest-value entrypoints in this module are:

  • load_patchworks_runtime_config() Load and validate the Patchworks runtime config file.

  • run_patchworks_preflight() Verify that the host, license, Java/Wine, and input artifacts are ready.

  • run_patchworks_command() Launch Matrix Builder or the app chooser and capture logs/manifests.

  • run_patchworks_beanshell_script() Launch Beanshell-based helper scripts through the same runtime shell.

  • build_patchworks_blocks_dataset() Prepare blocks.shp and optional topology CSV from the fragments dataset.

  • build_matrix_builder_command_string()

  • build_appchooser_command_string()

  • build_beanshell_command_string() Build the command text that the runtime layer will execute.

The main runtime payload classes are also useful because they define the core contracts explicitly:

  • PatchworksRuntimeConfig

  • PatchworksPreflightResult

  • PatchworksExecutionResult

  • PatchworksBlocksBuildResult

  • PatchworksConfigError

Runtime Contract Surfaces

The most important runtime contracts in this module are:

  • runtime config must contain valid patchworks and matrix_builder sections

  • the runtime must have a usable Java surface on Windows or a usable Wine + Java surface on non-Windows hosts

  • on known-good Windows workstations, licensing should usually resolve through the existing system-level SPS_LICENSE_SERVER environment value

  • patchworks.license_value is a fallback override seam and should not replace a valid system license setting unless that override is intentional

  • SPSHOME must point to the Patchworks install root visible to the chosen launcher mode

  • Matrix Builder requires a valid fragments dataset, output tracks directory, and ForestModel XML path before launch

  • runtime launches must emit logs/manifests even when the proprietary tool exits badly

This is the code-level owner of the runtime behavior documented in:

Host Modes And Launch Paths

One of the most important behaviors in this module is the host split:

  • on native Windows, FEMIC launches Java directly

  • on non-Windows hosts, FEMIC prefers Wine (wine64 or wine)

  • when patchworks.use_xvfb is enabled, non-Windows launches can be wrapped in xvfb-run -a

That host-mode split affects:

  • which executable FEMIC searches for

  • how paths are converted into Windows-visible arguments

  • where SPSHOME and license values must be visible

  • which failure signatures are expected during preflight versus runtime launch

If a command works on one host family but not the other, this module is where the behavior diverges intentionally.

Artifacts And Failure Seams

The most important runtime artifacts this module produces are:

  • patchworks_matrixbuilder_stdout-<run_id>.log

  • patchworks_matrixbuilder_stderr-<run_id>.log

  • patchworks_matrixbuilder_manifest-<run_id>.json

  • patchworks_beanshell_* logs/manifests for Beanshell runs

  • blocks/blocks.shp and optional topology_blocks_*r.csv

The common failure boundaries in this module are:

  • invalid runtime config missing required sections or malformed fields fail fast here

  • missing launcher/runtime prerequisites Java, Wine, patchworks.jar, SPSHOME, or license wiring may be absent even when the exported package itself is valid

  • fatal runtime stderr signatures Matrix Builder can “run” but still report fatal conditions only through stderr patterns that this module scans for explicitly

  • output-not-ready conditions a zero/empty tracks output directory after launch is treated as a runtime failure even if the JVM exit code is not obviously fatal

  • block/topology preparation problems missing fragments geometry, no usable stand/block id field, or backend misuse can break the build-blocks path before Matrix Builder ever runs

Headless Proving Ground

The native-Windows no-GUI proving-ground seam is now real in this module.

Current documented runtime rules:

  • let Control.waitForIterations(...) own scheduler startup in the BeanShell helper;

  • do not pre-issue control.resume() in the headless path or Patchworks can fail with java.lang.IllegalStateException: Not suspended;

  • FEMIC supervises the run by watching explicit headless trace/log markers and self-terminates the Patchworks Java tree on both success and failure.

The first useful headless scheduling proof used a tiny scenario mode, max-even-flow-smoke, on the K3Z proving-ground surface. The current best proof point is run p49_smoke_20260328q:

  • phase 1 seeds product.Yield.managed.Total with a modest annual minimum;

  • phase 2 suspends, activates flow.even.product.Yield.managed.Total, and runs a second bounded wait;

  • the saved stage records both targets as active in targetStatus.csv;

  • targetSummary.csv shows non-zero currents for both targets; and

  • schedule.csv remains non-empty (677 lines) with real managed treatments.

The normal CLI/default-target path is also now proven:

  • proving-ground smoke p49_smoke_20260328r omitted an explicit scenario target and relied on FEMIC’s default product.Yield.managed.Total resolution;

  • both the underlying target and the flow.even.* companion still ended up active in targetStatus.csv; and

  • schedule.csv remained non-empty (788 lines).

The current closeout-level proving ground is now the real base K3Z surface:

  • max-even-flow-smoke defaults to a useful K3Z recipe when the caller leaves --iterations at the placeholder value: target defaults to product.Yield.managed.Total and iterations default to 100000.

  • the BeanShell helper now seeds the underlying harvest target first and configures that base target with LINEAR=true, maximum = 200000 in all periods at default weight, and minimum = 10000 per period.

  • after the seed phase, the helper activates flow.even.product.Yield.managed.Total with minimum = maximum = 0 and minimum weight = maximum weight = 100 across all periods.

  • proving-ground smoke p49_base_closeout_20260328b ran against analysis/base.pin and saved a stage where both the underlying target and the even-flow companion were active, targetStatus.csv showed the base target with LINEAR=true, the base target summary stabilized around 122200 per period inside the 100000..200000 band, the even-flow target summary stayed tightly clustered near zero, and schedule.csv remained non-empty (480 lines).

That means this module now owns a real unattended Patchworks launch/analyze/ save/exit seam instead of a launch-only experiment.

Cross-References

Guides and references that pair especially closely with this module:

Related API pages:

Patchworks runtime helpers for Patchworks Matrix Builder execution.

class femic.patchworks_runtime.PatchworksBlocksBuildResult(model_dir, fragments_shapefile_path, blocks_shapefile_path, topology_csv_path, block_count, stand_id_field, topology_edge_count, topology_radius_m)[source]

Bases: object

Outputs from preparing a 1:1 stand:block blocks dataset.

Parameters:
  • model_dir (Path)

  • fragments_shapefile_path (Path)

  • blocks_shapefile_path (Path)

  • topology_csv_path (Path | None)

  • block_count (int)

  • stand_id_field (str)

  • topology_edge_count (int)

  • topology_radius_m (float)

block_count: int
blocks_shapefile_path: Path
fragments_shapefile_path: Path
model_dir: Path
stand_id_field: str
topology_csv_path: Path | None
topology_edge_count: int
topology_radius_m: float
exception femic.patchworks_runtime.PatchworksConfigError[source]

Bases: ValueError

Invalid Patchworks runtime config.

class femic.patchworks_runtime.PatchworksExecutionResult(run_id, command, command_string, returncode, stdout_log_path, stderr_log_path, manifest_path, failures, warnings=())[source]

Bases: object

Execution outputs for a Patchworks command launch.

Parameters:
  • run_id (str)

  • command (tuple[str, ...])

  • command_string (str)

  • returncode (int)

  • stdout_log_path (Path)

  • stderr_log_path (Path)

  • manifest_path (Path)

  • failures (tuple[str, ...])

  • warnings (tuple[str, ...])

command: tuple[str, ...]
command_string: str
failures: tuple[str, ...]
manifest_path: Path
returncode: int
run_id: str
stderr_log_path: Path
stdout_log_path: Path
warnings: tuple[str, ...] = ()
class femic.patchworks_runtime.PatchworksHeadlessRunResult(run_id, pin_path, stage_label, stage_dir, iterations, improvement, scenario_mode, scenario_target, scenario_min_annual, launcher_script_path, trace_log_path, execution, saved_file_count, failures)[source]

Bases: object

Execution outputs for an unattended Patchworks PIN run.

Parameters:
  • run_id (str)

  • pin_path (Path)

  • stage_label (str)

  • stage_dir (Path)

  • iterations (int)

  • improvement (float)

  • scenario_mode (str)

  • scenario_target (str | None)

  • scenario_min_annual (float | None)

  • launcher_script_path (Path)

  • trace_log_path (Path)

  • execution (PatchworksExecutionResult)

  • saved_file_count (int)

  • failures (tuple[str, ...])

execution: PatchworksExecutionResult
failures: tuple[str, ...]
improvement: float
iterations: int
launcher_script_path: Path
property manifest_path: Path

Return the headless-run manifest path.

pin_path: Path
property returncode: int

Return the effective run status code.

run_id: str
saved_file_count: int
scenario_min_annual: float | None
scenario_mode: str
scenario_target: str | None
stage_dir: Path
stage_label: str
trace_log_path: Path
class femic.patchworks_runtime.PatchworksPreflightResult(config, launcher_executable, host_mode, license_host, errors, warnings)[source]

Bases: object

Preflight report for Patchworks runtime execution.

Parameters:
  • config (PatchworksRuntimeConfig)

  • launcher_executable (str | None)

  • host_mode (str)

  • license_host (str | None)

  • errors (tuple[str, ...])

  • warnings (tuple[str, ...])

config: PatchworksRuntimeConfig
errors: tuple[str, ...]
host_mode: str
launcher_executable: str | None
license_host: str | None
property ok: bool

Return True when preflight checks reported no errors.

warnings: tuple[str, ...]
class femic.patchworks_runtime.PatchworksRuntimeConfig(config_path, jar_path, wine_prefix, license_env, license_value, spshome, use_xvfb, fragments_path, matrix_output_dir, forestmodel_xml_path, accounts_exclude_regex, harvested_volume_utilization_by_treatment, auto_close_window_on_success, auto_close_settle_seconds, auto_close_timeout_seconds)[source]

Bases: object

Resolved runtime settings for Patchworks execution.

Parameters:
  • config_path (Path)

  • jar_path (Path)

  • wine_prefix (Path | None)

  • license_env (str)

  • license_value (str)

  • spshome (str)

  • use_xvfb (bool)

  • fragments_path (Path)

  • matrix_output_dir (Path)

  • forestmodel_xml_path (Path)

  • accounts_exclude_regex (tuple[str, ...])

  • harvested_volume_utilization_by_treatment (dict[str, float])

  • auto_close_window_on_success (bool)

  • auto_close_settle_seconds (float)

  • auto_close_timeout_seconds (float)

accounts_exclude_regex: tuple[str, ...]
auto_close_settle_seconds: float
auto_close_timeout_seconds: float
auto_close_window_on_success: bool
config_path: Path
forestmodel_xml_path: Path
fragments_path: Path
harvested_volume_utilization_by_treatment: dict[str, float]
jar_path: Path
license_env: str
license_value: str
matrix_output_dir: Path
spshome: str
use_xvfb: bool
wine_prefix: Path | None
femic.patchworks_runtime.build_appchooser_command_string(config)[source]

Build Windows CMD command to open Patchworks app chooser.

Parameters:

config (PatchworksRuntimeConfig)

Return type:

str

femic.patchworks_runtime.build_beanshell_command_string(*, config, script_path, script_args=())[source]

Build Windows CMD command to run a BeanShell script via IProperties.

Parameters:
  • config (PatchworksRuntimeConfig)

  • script_path (Path)

  • script_args (tuple[str, ...])

Return type:

str

femic.patchworks_runtime.build_matrix_builder_command_string(config)[source]

Build the Windows CMD command to run Matrix Builder.

Parameters:

config (PatchworksRuntimeConfig)

Return type:

str

femic.patchworks_runtime.build_patchworks_blocks_dataset(*, config, model_dir=None, fragments_shapefile_path=None, topology_radius_m=200.0, build_topology=True, topology_backend='python')[source]

Build 1:1 stand:block blocks.shp (and optional topology CSV).

Parameters:
  • config (PatchworksRuntimeConfig)

  • model_dir (Path | None)

  • fragments_shapefile_path (Path | None)

  • topology_radius_m (float)

  • build_topology (bool)

  • topology_backend (Literal['python', 'patchworks-raster'])

Return type:

PatchworksBlocksBuildResult

femic.patchworks_runtime.find_wine_executable()[source]

Return preferred Wine executable path/name on PATH.

Return type:

str | None

femic.patchworks_runtime.format_command_for_display(command)[source]

Return shell-quoted command for human-readable logs.

Parameters:

command (tuple[str, ...])

Return type:

str

femic.patchworks_runtime.infer_patchworks_model_dir(config)[source]

Infer Patchworks model root from runtime input/output paths.

Parameters:

config (PatchworksRuntimeConfig)

Return type:

Path

femic.patchworks_runtime.is_windows_host()[source]

Return true when running on native Windows.

Return type:

bool

femic.patchworks_runtime.load_patchworks_runtime_config(path)[source]

Load and validate Patchworks runtime YAML/JSON config.

Parameters:

path (Path)

Return type:

PatchworksRuntimeConfig

femic.patchworks_runtime.parse_license_server(value)[source]

Parse user@server license format.

Parameters:

value (str)

Return type:

tuple[str, str]

femic.patchworks_runtime.run_patchworks_beanshell_script(*, config, script_path, script_args, log_dir, run_id=None)[source]

Execute a Patchworks BeanShell script via IProperties.

Parameters:
  • config (PatchworksRuntimeConfig)

  • script_path (Path)

  • script_args (tuple[str, ...])

  • log_dir (Path)

  • run_id (str | None)

Return type:

PatchworksExecutionResult

femic.patchworks_runtime.run_patchworks_command(*, config, interactive, log_dir, run_id=None)[source]

Execute Patchworks command and capture logs+manifest.

Parameters:
  • config (PatchworksRuntimeConfig)

  • interactive (bool)

  • log_dir (Path)

  • run_id (str | None)

Return type:

PatchworksExecutionResult

femic.patchworks_runtime.run_patchworks_headless_pin(*, config, pin_path, log_dir, run_id=None, stage_label=None, iterations=1, improvement=0.0, scenario_mode='none', scenario_target=None, scenario_min_annual=None)[source]

Run a Patchworks PIN unattended via the documented Patchworks seams.

Parameters:
  • config (PatchworksRuntimeConfig)

  • pin_path (Path)

  • log_dir (Path)

  • run_id (str | None)

  • stage_label (str | None)

  • iterations (int)

  • improvement (float)

  • scenario_mode (str)

  • scenario_target (str | None)

  • scenario_min_annual (float | None)

Return type:

PatchworksHeadlessRunResult

femic.patchworks_runtime.run_patchworks_preflight(*, config, require_matrix_inputs=True)[source]

Run preflight checks before Patchworks execution.

Parameters:
  • config (PatchworksRuntimeConfig)

  • require_matrix_inputs (bool)

Return type:

PatchworksPreflightResult

femic.patchworks_runtime.shutil_which(name)[source]

Wrapper for monkeypatch-friendly which lookup.

Parameters:

name (str)

Return type:

str | None

femic.patchworks_runtime.to_wine_windows_path(path)[source]

Map absolute path to a Windows-style path for command arguments.

Parameters:

path (Path)

Return type:

str