Source code for pasted._config

"""
pasted._config
==============
:class:`GeneratorConfig` — frozen dataclass that captures every parameter
accepted by :class:`~pasted._generator.StructureGenerator`.

Using a frozen dataclass instead of individual keyword arguments gives:

* Full mypy / IDE type-checking on every field
* Hashable, immutable config objects (safe to store, copy, and compare)
* ``dataclasses.replace(cfg, seed=99)`` for convenient one-field overrides
* A single variable to pass around instead of 30+ scattered kwargs

Relationship to the existing kwargs API
----------------------------------------
:func:`~pasted._generator.generate` still accepts plain keyword arguments
for backward compatibility — it constructs a :class:`GeneratorConfig`
internally.  New code is encouraged to build the config explicitly::

    from pasted import GeneratorConfig, StructureGenerator

    cfg = GeneratorConfig(n_atoms=12, charge=0, mult=1,
                          mode="gas", region="sphere:8",
                          elements="6,7,8", n_samples=50, seed=42)
    gen = StructureGenerator(cfg)
    result = gen.generate()

    # One-field override via dataclasses.replace (no mutation):
    cfg2 = dataclasses.replace(cfg, seed=99)
"""

from __future__ import annotations

from dataclasses import dataclass, field


[docs] @dataclass(frozen=True) class GeneratorConfig: """Immutable configuration for :class:`~pasted._generator.StructureGenerator`. All fields correspond exactly to the keyword parameters of :class:`~pasted._generator.StructureGenerator` and :func:`~pasted._generator.generate`. See those docstrings for full per-field documentation. The three fields without defaults (**n_atoms**, **charge**, **mult**) must always be supplied explicitly. Examples -------- Construct and pass to the class API:: from dataclasses import replace from pasted import GeneratorConfig, StructureGenerator cfg = GeneratorConfig( n_atoms=20, charge=0, mult=1, mode="gas", region="sphere:10", elements="6,7,8", n_samples=100, seed=0, ) result = StructureGenerator(cfg).generate() # Reuse with a different seed: result2 = StructureGenerator(replace(cfg, seed=1)).generate() Pass directly to the functional API:: from pasted import generate, GeneratorConfig cfg = GeneratorConfig(n_atoms=12, charge=0, mult=1, mode="chain", elements="6,7,8", n_samples=50, seed=42) result = generate(cfg) """ # ── Required fields (no default) ───────────────────────────────────── n_atoms: int charge: int mult: int # ── Placement mode ─────────────────────────────────────────────────── mode: str = "gas" region: str | None = None # ── Chain-mode parameters ───────────────────────────────────────────── branch_prob: float = 0.3 chain_persist: float = 0.5 chain_bias: float = 0.0 bond_range: tuple[float, float] = (1.2, 1.6) # ── Shell-mode parameters ───────────────────────────────────────────── center_z: int | None = None coord_range: tuple[int, int] = (4, 8) shell_radius: tuple[float, float] = (1.8, 2.5) # ── Element pool ───────────────────────────────────────────────────── elements: str | list[str] | None = None element_fractions: dict[str, float] | None = None element_min_counts: dict[str, int] | None = None element_max_counts: dict[str, int] | None = None # ── Physics / relaxation ───────────────────────────────────────────── cov_scale: float = 1.0 relax_cycles: int = 1500 #: Global affine transform strength. ``0.0`` disables (default). #: Individual operations can be overridden via *affine_stretch*, #: *affine_shear*, and *affine_jitter*. affine_strength: float = 0.0 #: Stretch/compress strength; falls back to *affine_strength* when ``None``. affine_stretch: float | None = None #: Shear strength; falls back to *affine_strength* when ``None``. affine_shear: float | None = None #: Per-atom jitter scale; falls back to *affine_strength* when ``None``. affine_jitter: float | None = None # ── Maxent-mode parameters ──────────────────────────────────────────── maxent_steps: int = 300 maxent_lr: float = 0.05 maxent_cutoff_scale: float = 2.5 trust_radius: float = 0.5 convergence_tol: float = 1e-3 # ── Hydrogen augmentation ───────────────────────────────────────────── add_hydrogen: bool = True # ── Sampling control ───────────────────────────────────────────────── n_samples: int = 1 n_success: int | None = None seed: int | None = None # ── Metric computation ──────────────────────────────────────────────── n_bins: int = 20 w_atom: float = 0.5 w_spatial: float = 0.5 cutoff: float | None = None # ── Filters & verbosity ─────────────────────────────────────────────── filters: list[str] | None = field(default=None) verbose: bool = False