geoprior.models.subsidence.scaling#

GeoPrior scaling config helpers (Keras-serializable).

Functions

override_scaling_kwargs(sk, cfg, *[, ...])

Override scaling_kwargs from a JSON file or dict.

Classes

GeoPriorScalingConfig([payload, source, ...])

Scaling configuration utilities for GeoPrior PINN.

class geoprior.models.subsidence.scaling.GeoPriorScalingConfig(payload=<factory>, source=None, schema_version='1')[source]#

Bases: object

Scaling configuration utilities for GeoPrior PINN.

This module defines GeoPriorScalingConfig, a small Keras-serializable container used to store and reconstruct the physics scaling and slicing controls used by GeoPriorSubsNet.

The scaling configuration is critical because it governs how coordinates, time units, groundwater variables, and physics residuals are interpreted and non-dimensionalized. If this configuration is not faithfully serialized via Keras get_config(), a reloaded model may be reconstructed with a different effective physics behavior.

The main entry point is GeoPriorScalingConfig.from_any(), which accepts a dict-like mapping, a file path str, or an existing GeoPriorScalingConfig instance. The resolved configuration is produced by resolve(), which runs the same canonicalization and validation pipeline used during training.

Notes

  • The resolved scaling dictionary should be JSON-safe and stable under Keras serialization.

  • Use _jsonify() to defensively convert nested values (NumPy scalars, tuples, sets) into plain Python types.

  • The config container combines Keras serialization patterns with the standard-library dataclass model [16, 17].

See also

load_scaling_kwargs

Load scaling configuration from mapping or file.

canonicalize_scaling_kwargs

Normalize keys and fill defaults consistently.

enforce_scaling_alias_consistency

Ensure alias keys agree and do not conflict.

validate_scaling_kwargs

Validate schema and value ranges.

Parameters:
  • payload (dict)

  • source (str | None)

  • schema_version (str)

payload: dict#
source: str | None = None#
schema_version: str = '1'#
classmethod from_any(obj, *, copy=True)[source]#

Serializable container for GeoPrior scaling configuration.

This dataclass stores a “payload” dictionary that holds all scaling and physics-control parameters required to reproduce the model behavior after saving and reloading with Keras.

The container supports flexible construction from: - None (empty config), - a mapping (dict-like), - a file path str (loaded via load_scaling_kwargs), - an existing GeoPriorScalingConfig instance.

The canonical and validated configuration is produced by resolve(), which applies the GeoPrior scaling pipeline: loading, canonicalization, alias consistency checks, and validation.

Parameters:
  • payload (dict, optional) – Raw scaling configuration payload. This may be incomplete or contain aliases prior to canonicalization.

  • source (str or None, optional) – Optional provenance string, typically a file path used to load the payload. This is stored for traceability only.

  • schema_version (str, optional) – Version label for the payload schema. This can be used to implement migrations when the scaling format evolves.

Variables:
  • payload (dict) – The raw payload stored in this object.

  • source (str or None) – The provenance hint, if provided.

  • schema_version (str) – Schema version label.

Notes

  • The resolved scaling dictionary returned by resolve() is the one you should pass to the model internals.

  • get_config returns JSON-safe objects only. This avoids subtle reconstruction drift caused by non-serializable values.

  • This factory aligns with the Keras object-serialization pattern described in Keras Team [16].

Examples

Construct from a mapping:

>>> cfg = GeoPriorScalingConfig.from_any(
...     {"coords_normalized": True}
... )
>>> sk = cfg.resolve()
>>> isinstance(sk, dict)
True

Construct from a file path:

>>> cfg = GeoPriorScalingConfig.from_any(
...     "path/to/scaling_kwargs.json"
... )
>>> sk = cfg.resolve()

Use in a model constructor (pattern):

>>> cfg = GeoPriorScalingConfig.from_any(scaling_kwargs)
>>> scaling_kwargs_resolved = cfg.resolve()

See also

GeoPriorScalingConfig.from_any

Build config from dict, path, or config instance.

GeoPriorScalingConfig.resolve

Produce canonical and validated scaling dictionary.

load_scaling_kwargs, canonicalize_scaling_kwargs

resolve()[source]#

Resolve the payload into a canonical, validated scaling dict.

This method runs the GeoPrior scaling pipeline and returns a dictionary suitable for direct use inside model computations.

The pipeline is: 1) Load payload (mapping or file-style behavior), 2) Canonicalize keys and fill defaults, 3) Enforce alias consistency, 4) Validate values and required fields.

Returns:

scaling_kwargs – Canonical and validated scaling configuration.

Return type:

dict

Raises:
  • ValueError – If validation fails due to missing keys or invalid values.

  • KeyError – If canonicalization expects keys that are absent.

  • TypeError – If the payload contains unsupported types.

Notes

  • The returned dict is intended to be stable under Keras serialization and safe to store in model state.

  • This method always loads with copy=True to avoid mutating the stored payload.

Examples

>>> cfg = GeoPriorScalingConfig.from_any(
...     {"coords_normalized": True}
... )
>>> sk = cfg.resolve()
>>> sk["coords_normalized"]
True

See also

canonicalize_scaling_kwargs

Normalizes scaling keys and defaults.

validate_scaling_kwargs

Enforces schema and constraints.

enforce_scaling_alias_consistency

Prevents conflicting aliases.

get_config()[source]#

Return a JSON-safe Keras configuration dictionary.

Keras uses this method to serialize the object. The returned dictionary must contain only JSON-serializable values.

This implementation uses _jsonify() to defensively convert nested structures such as NumPy scalars, tuples, and sets into plain Python types.

Returns:

config – JSON-safe configuration dictionary with the following keys: - payload: JSON-safe payload mapping, - source: provenance hint (may be None), - schema_version: schema version label.

Return type:

dict

Notes

  • source is stored for traceability and does not affect resolve().

  • When saved as part of a model config, this makes scaling reconstruction deterministic.

See also

GeoPriorScalingConfig.from_config

Recreate a config instance from this dictionary.

classmethod from_config(config)[source]#

Recreate an instance from a Keras configuration dictionary.

This class method is used by Keras deserialization to rebuild the object from the dictionary returned by get_config().

Parameters:

config (dict) – Configuration dictionary produced by get_config().

Returns:

cfg – Reconstructed config instance.

Return type:

GeoPriorScalingConfig

Notes

  • This method does not call resolve(). Resolution is deferred to the consumer so that reconstruction remains explicit and testable.

See also

GeoPriorScalingConfig.get_config

Produces the configuration dictionary.

__init__(payload=<factory>, source=None, schema_version='1')#
Parameters:
  • payload (dict)

  • source (str | None)

  • schema_version (str)

Return type:

None

geoprior.models.subsidence.scaling.override_scaling_kwargs(sk, cfg, *, finalize=None, dyn_names=None, gwl_dyn_index=None, base_dir=None, path_key='SCALING_KWARGS_JSON_PATH', strict=True, add_path=True, log_fn=None)[source]#

Override scaling_kwargs from a JSON file or dict.

This helper applies an optional, precedence-based override to an existing scaling_kwargs mapping. The override source is read from cfg[path_key]. If the key is missing or empty, the input sk is returned (optionally finalized).

The override can be provided as:

  • a file path to a JSON object (mapping), or

  • a Python dict-like mapping embedded in cfg.

Overrides are applied via a deep-merge strategy:

  • for nested dict values, keys are merged recursively,

  • for non-dict values, the override replaces the base value.

Optionally, the merged result is passed through finalize to recompute derived or canonical fields (for example, coordinate ranges, unit flags, or other normalization metadata).

Parameters:
  • sk (Mapping[str, Any]) – Base scaling configuration (scaling_kwargs). This is typically computed by Stage-2 or loaded from Stage-1 output. The input is copied to a plain dict before modification.

  • cfg (Mapping[str, Any] or None) – Configuration mapping that may contain the override source under path_key. If None, no override is applied.

  • finalize (callable or None, optional) –

    Function applied to the scaling dict to enforce canonical structure or to compute derived fields. If provided, it is applied before and after the override merge:

    • pre-merge: normalize the base dict,

    • post-merge: ensure the merged dict is consistent.

    The callable must accept a dict and return a dict.

  • dyn_names (Sequence[str] or None, optional) – Expected dynamic feature names for safety validation. If provided and the override contains dynamic_feature_names, the two sequences are compared. A mismatch raises an error when strict=True.

  • gwl_dyn_index (int or None, optional) – Expected dynamic index for the groundwater-level feature. If provided and the override contains gwl_dyn_index, the values are compared. A mismatch raises an error when strict=True.

  • base_dir (str or None, optional) – Base directory used to resolve relative JSON paths. If None, the current working directory is used.

  • path_key (str, default "SCALING_KWARGS_JSON_PATH") – Name of the key in cfg that specifies the override. The value may be a dict-like mapping or a path to a JSON file.

  • strict (bool, default True) – Controls behavior on safety-check mismatches. When True, mismatches raise a ValueError. When False, mismatches can be logged via log_fn and the override still proceeds.

  • add_path (bool, default True) – If True, store the resolved override source in the output dict under scaling_kwargs_override_path. When the override is provided as a mapping (not a file), the value is set to "<dict>".

  • log_fn (callable or None, optional) – Optional logger function. If provided, it is called with informative messages such as successful override application and (when strict=False) mismatch warnings. Common choices are print or logger.info.

Returns:

out – Final scaling dict after optional override and optional finalization. The returned dict is independent from the input mapping object sk (a copy is always created).

Return type:

dict

Raises:
  • FileNotFoundError – If cfg[path_key] is a path and the file does not exist.

  • ValueError – If a path is provided but the file does not contain valid JSON, or if a safety check fails while strict=True.

  • TypeError – If the loaded override is not a JSON object (dict-like).

Notes

Path resolution

When cfg[path_key] is a string path, it is resolved as:

  1. Expand environment variables and ~.

  2. If relative, join with base_dir (or CWD).

Safety checks

The checks are intentionally conservative. They prevent using an override file produced for a different dataset or feature layout. Recommended checks are:

  • dynamic_feature_names equality when known.

  • gwl_dyn_index equality when known.

You can extend validation by checking additional keys such as coord_epsg_used, coords_normalized, or unit flags.

Finalization In GeoPrior pipelines, finalize is typically a helper that enforces defaults and recomputes derived entries. Applying it both before and after the override helps reduce edge cases where the override only supplies partial information.

Figure assembly follows the plotting conventions described in Hunter [15].

Examples

Stage-2: override computed scaling with a file

In Stage-2, call this right after the auto-computed scaling is available, so the override takes precedence:

>>> sk = subsmodel_params["scaling_kwargs"]
>>> sk = override_scaling_kwargs(
...     sk,
...     cfg,
...     finalize=finalize_scaling_kwargs,
...     dyn_names=DYN_NAMES,
...     gwl_dyn_index=GWL_DYN_INDEX,
...     base_dir=os.path.dirname(__file__),
...     strict=True,
...     log_fn=print,
... )
>>> subsmodel_params["scaling_kwargs"] = sk
Stage-3: override Stage-1 scaling prior to enforcing bounds

In Stage-3, apply the override before injecting Stage-3 bounds:

>>> sk_model = dict(cfg.get("scaling_kwargs", {}) or {})
>>> sk_model = override_scaling_kwargs(
...     sk_model,
...     cfg,
...     dyn_names=sk_model.get("dynamic_feature_names"),
...     gwl_dyn_index=sk_model.get("gwl_dyn_index"),
...     base_dir=os.path.dirname(__file__),
... )
>>> sk_model["bounds"] = {
...     **(sk_model.get("bounds", {}) or {}),
...     **bounds_for_scaling,
... }
Inline dict override (no JSON file)

If the override is embedded in config, it is used directly:

>>> cfg = {
...     "SCALING_KWARGS_JSON_PATH": {
...         "coords_normalized": True,
...         "coord_ranges": {"t": 7.0, "x": 1000.0, "y": 900.0},
...     }
... }
>>> out = override_scaling_kwargs({}, cfg)

See also

finalize_scaling_kwargs

Canonicalize and complete scaling_kwargs entries.

compute_scaling_kwargs

Build a base scaling dict from data and pipeline settings.