Source code for strongcoca.compute_config

from dataclasses import dataclass
from typing import Optional

_VALID_BACKENDS = ('none', 'torch', 'cupy')
_VALID_PRECISIONS = ('float32', 'float64')


[docs] @dataclass(frozen=True) class ComputeConfig: """Global runtime configuration for the O(N³) linear-algebra operations in :class:`~strongcoca.calculators.PolarizabilityCalculator`. Parameters ---------- backend ``'none'`` (CPU only), ``'torch'`` (PyTorch/CUDA), or ``'cupy'`` (CuPy/CUDA). precision Floating-point precision for GPU operations. ``'float32'`` casts to complex64 before the GPU kernel and back to complex128 afterwards (roughly 10x faster on consumer GPUs where FP64 throughput is restricted); ``'float64'`` keeps complex128 throughout. max_solve_mem Memory budget in MiB for intermediate matrices in the CPU linear solve step. The frequency axis is chunked so that the A matrix stays below this limit. gpu_batched_max Maximum value of N3 = 3 x N_particles for which the cuBLAS batched solver is used in GPU kernels. Above this threshold, the code loops over the batch dimension to invoke the non-batched cuSOLVER path, which is faster for large matrices on consumer GPUs. Increase this value (e.g. to 1024 or higher) on A100/H100/H200 cards, where the batched cuSOLVER path performs well at large N. """ backend: str precision: str max_solve_mem: float gpu_batched_max: int
_config = ComputeConfig(backend='none', precision='float32', max_solve_mem=80.0, gpu_batched_max=32)
[docs] def set_compute_config(backend: Optional[str] = None, precision: Optional[str] = None, max_solve_mem: Optional[float] = None, gpu_batched_max: Optional[int] = None) -> None: """Update one or more fields of the global compute configuration. Any argument left as ``None`` keeps its current value. All arguments are validated before anything is written, so an invalid call leaves the configuration completely unchanged. Parameters ---------- backend See :class:`ComputeConfig`. precision See :class:`ComputeConfig`. max_solve_mem See :class:`ComputeConfig`. gpu_batched_max See :class:`ComputeConfig`. Examples -------- >>> from strongcoca import set_compute_config, get_compute_config >>> set_compute_config(max_solve_mem=200) >>> get_compute_config().max_solve_mem 200.0 >>> set_compute_config(max_solve_mem=80) # reset to the default """ global _config new_backend = _config.backend if backend is None else backend new_precision = _config.precision if precision is None else precision new_max_solve_mem = _config.max_solve_mem if max_solve_mem is None else float(max_solve_mem) new_gpu_batched_max = _config.gpu_batched_max if gpu_batched_max is not None: new_gpu_batched_max = int(gpu_batched_max) if new_backend not in _VALID_BACKENDS: raise ValueError(f'backend must be one of {_VALID_BACKENDS}, got {new_backend!r}') if new_precision not in _VALID_PRECISIONS: raise ValueError(f'precision must be one of {_VALID_PRECISIONS}, got {new_precision!r}') if new_max_solve_mem <= 0: raise ValueError(f'max_solve_mem must be positive, got {new_max_solve_mem}') if new_gpu_batched_max <= 0: raise ValueError(f'gpu_batched_max must be positive, got {new_gpu_batched_max}') _config = ComputeConfig(backend=new_backend, precision=new_precision, max_solve_mem=new_max_solve_mem, gpu_batched_max=new_gpu_batched_max)
[docs] def get_compute_config() -> ComputeConfig: """Return the current global compute configuration.""" return _config