Inference utilities#

Condition-spec input#

Orchestration for the YAML/JSON condition-spec format.

See design_yaml_condition_spec.md / docs/condition_spec_yaml.md: a condition spec is a shorthand for building an annotated CIF – load input structure(s) (§4.2), subset + insert expandable segments via one contig string (§4.3), set Conditions/StandardAnnotations by name (§4.4), then finalize (§4.5: pre-save validation + a “summarize changes” report, no explicit back-fill). build_annotated_atom_array_from_condition_spec() does all of this for one example; resolve_condition_spec_inputs() does it for every example in a spec file and writes each to disk.

rfproteina.inference_utils.condition_spec.split_global_args(spec: dict) → dict[str, dict][source]#

Return {example_id: merged_example}, folding top-level global_args into each example.

Raises:

ValueError – If global_args or any example is not a mapping. Skipping such entries instead would silently drop a whole example on a small indentation mistake, producing a run with fewer designs than the author asked for.

rfproteina.inference_utils.condition_spec.is_legacy_dialect(data: dict) → bool[source]#

Whether data is written in the removed legacy contig-JSON dialect.

There’s no explicit marker to check for – the legacy dialect predated condition_spec existing at all. Instead, this looks at each example’s own field names (with global_args defaults folded in): condition_spec’s input key is required (missing it raises KeyError downstream), so an example lacking it can’t be condition_spec; and any field name outside condition_spec’s small vocabulary – i.e. any of the legacy-only names in _LEGACY_ONLY_FIELDS (select_fixed_atoms, unindex, the per-example dialect int, …) – is unambiguous evidence of the legacy one. Every legacy example ends up naming at least one such field (a fully-diffused example uses length/contig alone, neither of which condition_spec needs). The legacy path itself is gone, so callers use this only to reject such inputs with a clear migration error.

Parameters:

data – A loaded spec file (as returned by load_spec_file()), global_args key included.

Returns:

True if any example (or global_args) looks like the legacy dialect.

rfproteina.inference_utils.condition_spec.load_condition_spec_inputs(paths: list[str | PathLike], *, as_annotated_cif: bool = False) → AtomArrayPlus[source]#

Parse and combine one or more structure files into a single AtomArrayPlus (§4.2). Loads the asymmetric unit only (build_assembly=None).

Parameters:
  • paths – One or more CIF or BinaryCIF paths, optionally gzip- or Zstandard-compressed.

  • as_annotated_cif – If True, load any existing Condition/StandardAnnotation columns already present (e.g. re-editing a previous output of this tool). If False (default), any existing conditioning is ignored.

Returns:

The combined structure.

Raises:

ValueError – If any input isn’t a CIF/BCIF file, or if chain_id collides across multiple input files.

rfproteina.inference_utils.condition_spec.load_example_input(spec: dict, spec_dir: Path) → AtomArrayPlus[source]#

Load one example’s input: structure(s), before contig subsetting (§4.2).

rfproteina.inference_utils.condition_spec.build_annotated_atom_array_from_condition_spec(spec: dict, *, spec_dir: Path, example_id: str = 'example', strict: bool = True, validate: bool = False) → dict[source]#

Build one example’s fully assembled + annotated structure from its condition-spec dict.

Runs the fixed order of operations (companion doc): load (§4.2), contig (§4.3), conditions (§4.4), finalize (§4.5).

Parameters:
  • spec – One example’s {input, input_as_annotated_cif, contig, conditions} dict.

  • spec_dir – Directory the spec file itself lives in (relative input paths resolve against this).

  • example_id – Name used in the printed summary and validation error messages.

  • strict – If True (default), a failed pre-save validation check raises instead of only logging a warning.

  • validate – If True, run the (slow) pre-save validation. Defaults to False – online inference validates via the dataset transform instead; only the CIF-writer script and prevalidate_inputs=true opt in (see _prevalidate()).

Returns:

{atom_array, chain_info, ligand_info, metadata}, the same shape parse_atom_array() returns.

rfproteina.inference_utils.condition_spec.load_spec_file(path: Path) → dict[source]#

Load a condition-spec file (YAML or JSON, by extension) into a raw dict.

rfproteina.inference_utils.condition_spec.write_condition_spec_cif(example_id: str, spec: dict, out_path: Path, *, spec_dir: Path, validate: bool = True) → Path[source]#

Build one example and write it to disk as an annotated CIF.

Parameters:
  • example_id – Example name (used in the printed summary).

  • spec – One example’s condition-spec dict.

  • out_path – Destination CIF path.

  • spec_dir – Directory the spec file lives in (for resolving relative input paths).

  • validate – If True (default), run pre-save validation on the built structure.

Returns:

out_path.

rfproteina.inference_utils.condition_spec.resolve_condition_spec_inputs(path: str | PathLike, out_dir: str | PathLike | None = None, *, validate: bool = True) → list[Path][source]#

Build every example in a condition-spec file and write each to disk as an annotated CIF.

Parameters:
  • path – Path to a condition_spec YAML/JSON file.

  • out_dir – Directory to write the CIFs into. Defaults to <spec_stem>_cifs/ beside the spec.

  • validate – If True (default), run pre-save validation on each built structure.

Returns:

The list of written CIF paths, in file declaration order.

Raises:

ValueError – If path is a legacy contig-JSON file (unsupported by this writer).

Metric aggregation#

Concatenate and aggregate per-example metrics from multi-job evaluation runs.

rfproteina.inference_utils.aggregate_metrics.aggregate_sequence_probability_errors(per_example_df: DataFrame, workers: int | None = None) → DataFrame[source]#

Pool soft probability observations across designs before computing per-task errors.

Returns:

One row per dataset/task with n (number of pairs), absolute_mass_error (abs(sum(q - p))), mean_absolute_error, and median_absolute_error. Empty when no soft probability conditions were evaluated. Missing or unreadable structures are skipped with a warning.

rfproteina.inference_utils.aggregate_metrics.aggregate_metrics_from_per_example_df(per_example_df: DataFrame, title: str = 'Aggregated Metrics', group_by: str = 'dataset_name') → DataFrame[source]#

Aggregate per-example metrics by a grouping column.

Parameters:
  • per_example_df – DataFrame with columns including ‘example_id’, ‘dataset_name’, and metric columns.

  • title – Title for the printed table.

  • group_by – Column to group by.

Returns:

<group_by>, n, and one column per metric.

Return type:

DataFrame with one row per group value, columns

rfproteina.inference_utils.aggregate_metrics.concatenate_results(input: str, cluster_with_foldseek: bool = False, cleanup: bool = True, cleanup_chains: bool = True, output_dir: str | None = None, foldseek_threads: int | None = None, sequence_probability_workers: int | None = None) → None[source]#

Concatenate per-example and aggregated metrics from multiple jobs.

Can also be used to run foldseek post-hoc by calling on the output dataframe.

Parameters:
  • input – Path to either the directory containing the individual job result files, or the already-concatenated per_example_metrics.csv file.

  • cluster_with_foldseek – Whether to cluster results using Foldseek.

  • cleanup – If True, move individual job files to a subdirectory after concatenation.

  • cleanup_chains – If True (default), delete the foldseek_input_chains/ directory after clustering completes. The chain CIF files are derived from the designed structures and can be regenerated, so removal is safe.

  • output_dir – Directory where results should be saved. Defaults to the input directory (or parent directory when input is a file).

  • foldseek_threads – Number of CPU threads to pass to foldseek. Defaults to all available CPUs. Set explicitly when running multiple clustering jobs in parallel on the same node to avoid resource contention.

  • sequence_probability_workers – Number of processes used to reconstruct probability observations from output CIFs. Defaults to up to eight CPUs from the SLURM allocation or process affinity; set explicitly to use more.

rfproteina.inference_utils.aggregate_metrics.main() → None[source]#