pyfracval.event_log =================== .. py:module:: pyfracval.event_log .. autoapi-nested-parse:: Structured, append-only event log for aggregate generation. Existing telemetry answers "did this run succeed". A paper needs something else: **where** generation fails, **why**, and **how badly** - pooled over thousands of runs and sliceable by the physics (``Df``, ``kf``, ``sigma_p,geo``, ``N``). Free-text log lines cannot be aggregated, and the in-memory ``diagnostics`` dict ``run_simulation`` accepts is per-call and never persisted. This module writes one JSONL file carrying three record kinds, each stamped with the same run context so they can be sliced or joined together: ``merge`` One CCA merge attempt: which round, which cluster pair, the contact distance attempted, how much of the search was consumed, the outcome, and - when a census ran - how many particles ended up overlapping and by how much. ``pca_failure`` A PCA subcluster that could not be built: at which particle index, with how many candidate partners available, after how many search/swap attempts. Without this, "where does it fail" cannot distinguish a PCA failure from a CCA one with any detail, even though both occur. ``run`` One completed or abandoned aggregate: outcome, failure stage and reason, attempts consumed, wall time, and the final geometry's measured quality. Enable with ``OrchestratorAlgorithmConfig.event_log_path``. Nothing is written and no file is opened when it is unset. Concurrency: records are written as single ``write()`` calls of one line each in append mode, which is atomic enough on POSIX for several Dask workers to share one path. Every record carries ``run_id`` and ``pid`` so interleaved lines can always be separated again. Module Contents --------------- .. py:class:: MergeEvent One CCA merge attempt between two clusters. .. attribute:: round_index Which CCA round (1-based). Round 1 merges the initial PCA subclusters - the round essentially every hard-regime failure occurs in (docs/source/pairing_frustration.md). :type: int .. attribute:: pool_size Number of clusters in the pool at the start of this round. :type: int .. attribute:: cluster_idx1, cluster_idx2 Indices of the two clusters within the round's pool. :type: int .. attribute:: n1, n2 Particle counts of the two clusters. :type: int .. attribute:: gamma_pc Scaling-law contact distance the merge was attempted at. :type: float .. attribute:: gamma_real Whether the Gamma equation had a real solution at all. :type: bool .. attribute:: sum_rmax ``r_max1 + r_max2``; the cheap feasibility gate compares this against ``gamma_pc``. :type: float .. attribute:: outcome One of ``stuck``, ``stuck_relaxed_tol``, ``failed_no_candidates``, ``failed_overlap``, ``rescued_soft_relaxation``, ``rescued_drop``, ``failed_gamma_not_real``, ``skipped_bv_filter``. :type: str .. attribute:: candidates_tried Number of candidate (s1, s2) monomer pairs attempted. :type: int .. attribute:: n_feasible_pairs Size of the candidate matrix - the search space available. :type: int .. attribute:: rotations_used Rotation steps consumed on the final candidate attempted. :type: int .. attribute:: min_overlap Best (smallest) max-overlap reached, normalized by ``r_i + r_j`` so it is directly comparable to ``tol_ov``. :type: float .. attribute:: n_offending_particles Distinct particles involved in a residual overlap at give-up. :type: int | None .. attribute:: n_pairs_overlapping Overlapping pairs at give-up. :type: int | None .. attribute:: max_overlap_of_rsum Worst residual overlap at give-up, normalized by ``r_i + r_j`` and therefore comparable to ``tol_ov``. :type: float | None .. attribute:: max_overlap_of_rmin The same overlap normalized by ``min(r_i, r_j)``. Recorded separately because the two denominators differ by a large factor for wide size distributions and must never be conflated. :type: float | None .. attribute:: n_particles_dropped Particles removed by drop-rescue, when that fallback succeeded. :type: int .. attribute:: attempt_index 0-based index of this partner attempt for ``cluster_idx1`` within the round; non-zero only under backtracking pairing, and what distinguishes "first choice worked" from "third choice worked". :type: int .. py:class:: PcaFailureEvent A PCA subcluster that could not be completed. PCA failure is a distinct mechanism from CCA sticking failure: it happens while growing a *single* subcluster particle by particle, and the usual cause is that no already-placed particle sits at a workable distance for the next monomer's Gamma. Recording it separately is what lets a failure taxonomy attribute blame correctly instead of lumping everything under "the run failed". .. py:class:: RunEvent One aggregate generation attempt, start to finish. .. py:class:: EventLog(path, context = None, run_id = None) Append-only JSONL sink for generation events. .. py:method:: set_context(**kwargs) Merge additional fields into the per-record context. .. py:method:: record(event) Append one event. Never raises: logging is diagnostic, and a full disk or bad path must not abort an aggregate mid-build.