beach.io.types のソースコード

"""Public data types for Fortran output handling."""

from __future__ import annotations

from dataclasses import dataclass, field as dataclass_field
from pathlib import Path
from typing import TYPE_CHECKING

import numpy as np

if TYPE_CHECKING:
    from .history import BatchHistory


[ドキュメント] @dataclass(frozen=True) class MeshSource: """Metadata for one source mesh record. Attributes ---------- mesh_id : int Mesh identifier written in ``mesh_sources.csv``. source_kind : str Mesh source category (for example ``"template"`` or ``"obj"``). template_kind : str Template subtype when ``source_kind`` is ``"template"``. elem_count : int Number of triangle elements belonging to the mesh. surface_model : str Surface response model for this mesh group. epsilon_r : float Relative permittivity associated with this mesh group. """ mesh_id: int source_kind: str template_kind: str elem_count: int surface_model: str = "insulator" epsilon_r: float = 1.0
[ドキュメント] @dataclass(frozen=True) class MeshSelection: """Selection of one or more meshes extracted from one run. Attributes ---------- directory : pathlib.Path Output directory this selection belongs to. mesh_ids : tuple of int Mesh identifiers included in this selection. elem_indices : numpy.ndarray Original element indices in the full mesh arrays. triangles : numpy.ndarray Selected triangle coordinates with shape ``(n_elem, 3, 3)``. charges : numpy.ndarray Selected per-element charges with shape ``(n_elem,)``. step : int or None, default None History batch step used for the charge snapshot. """ directory: Path mesh_ids: tuple[int, ...] elem_indices: np.ndarray triangles: np.ndarray charges: np.ndarray step: int | None = None
[ドキュメント] @dataclass(frozen=True) class CoulombInteraction: """Coulomb force/torque summary between two mesh groups. Attributes ---------- group_a_mesh_ids : tuple of int Mesh ids used as the target group. group_b_mesh_ids : tuple of int Mesh ids used as the source group. step : int or None History step used for the interaction snapshot. torque_origin_m : numpy.ndarray Torque origin in meters with shape ``(3,)``. force_on_a_N : numpy.ndarray Net force on group A in newtons with shape ``(3,)``. force_on_b_N : numpy.ndarray Net force on group B in newtons with shape ``(3,)``. torque_on_a_Nm : numpy.ndarray Net torque on group A in newton-meters with shape ``(3,)``. torque_on_b_Nm : numpy.ndarray Net torque on group B in newton-meters with shape ``(3,)``. mean_force_on_a_per_element_N : numpy.ndarray Mean force per target element in newtons with shape ``(3,)``. mean_torque_on_a_per_element_Nm : numpy.ndarray Mean torque per target element in newton-meters with shape ``(3,)``. """ group_a_mesh_ids: tuple[int, ...] group_b_mesh_ids: tuple[int, ...] step: int | None torque_origin_m: np.ndarray force_on_a_N: np.ndarray force_on_b_N: np.ndarray torque_on_a_Nm: np.ndarray torque_on_b_Nm: np.ndarray mean_force_on_a_per_element_N: np.ndarray mean_torque_on_a_per_element_Nm: np.ndarray
[ドキュメント] @dataclass(frozen=True) class CoulombMobilityRecord: """Per-object Coulomb mobility summary. Attributes ---------- mesh_id : int Mesh identifier of the analyzed object. label : str Human-readable object label. kind : str Object kind resolved from ``beach.toml`` or ``mesh_sources.csv``. step : int or None History step used for the analysis snapshot. center_m : numpy.ndarray Object centroid in meters with shape ``(3,)``. force_N : numpy.ndarray Net Coulomb force in newtons with shape ``(3,)``. torque_Nm : numpy.ndarray Net Coulomb torque about object center in newton-meters with shape ``(3,)``. force_normal_N : float Force component along support normal. Positive means lift direction. force_tangent_N : float Tangential-force magnitude relative to the support normal. torque_normal_Nm : float Torque component along support normal. torque_tangent_Nm : float Tangential-torque magnitude relative to the support normal. mass_kg : float or None Estimated object mass. ``None`` when geometry or density is unavailable. characteristic_radius_m : float or None Characteristic radius used for rolling metrics when available. weight_support_N : float or None Weight component resisted by the support normal. resisting_normal_N : float or None Baseline normal resistance used for lift checks (typically weight + adhesion). effective_normal_load_N : float or None Remaining compressive normal load after Coulomb lift is applied. lift_ratio : float or None ``max(force_normal, 0) / resisting_normal`` when available. slide_ratio : float or None ``force_tangent / (mu_static * effective_normal_load)`` when available. roll_ratio : float or None ``torque_tangent / (mu_roll * effective_normal_load * radius)`` when available. notes : tuple of str Diagnostic notes about unavailable assumptions or approximations. """ mesh_id: int label: str kind: str step: int | None center_m: np.ndarray force_N: np.ndarray torque_Nm: np.ndarray force_normal_N: float force_tangent_N: float torque_normal_Nm: float torque_tangent_Nm: float mass_kg: float | None characteristic_radius_m: float | None weight_support_N: float | None resisting_normal_N: float | None effective_normal_load_N: float | None lift_ratio: float | None slide_ratio: float | None roll_ratio: float | None notes: tuple[str, ...] = ()
[ドキュメント] @dataclass(frozen=True) class CoulombMobilityAnalysis: """Collection of per-object Coulomb mobility records. Attributes ---------- step : int or None History step used for the analysis snapshot. gravity_m_s2 : numpy.ndarray Gravity vector in meters per second squared with shape ``(3,)``. support_normal_m : numpy.ndarray Unit support normal with shape ``(3,)``. support_kinds : tuple of str Object kinds treated as supports and excluded by default from targets. density_kg_m3 : float or None Bulk density used for mass estimation. mu_static : float or None Static-friction coefficient used for slide checks. mu_roll : float or None Rolling-resistance coefficient used for roll checks. adhesion_force_N : float Additional normal adhesion resisting lift. records : tuple of CoulombMobilityRecord Per-object analysis records. """ step: int | None gravity_m_s2: np.ndarray support_normal_m: np.ndarray support_kinds: tuple[str, ...] density_kg_m3: float | None mu_static: float | None mu_roll: float | None adhesion_force_N: float records: tuple[CoulombMobilityRecord, ...]
[ドキュメント] @dataclass(frozen=True) class ChargeLedgerEntry: """One species row from ``charge_ledger.csv``.""" batch: int species_idx: int injected_from_remote_c: float emitted_from_surface_c: float absorbed_on_surface_c: float escaped_to_infinity_c: float discarded_unresolved_c: float injected_count: int emitted_count: int absorbed_count: int escaped_count: int discarded_unresolved_count: int neutral_return_correction_c: float = 0.0 neutral_return_weight_scale: float = 1.0 neutral_return_unresolved_fraction: float = 0.0 fixed_absorbed_target_charge_c: float = 0.0 fixed_absorbed_applied_charge_c: float = 0.0 fixed_absorbed_weight_scale: float = 1.0 fixed_emission_target_charge_c: float = 0.0 fixed_emission_applied_charge_c: float = 0.0 fixed_emission_weight_scale: float = 1.0 fixed_escape_target_charge_c: float = 0.0 fixed_escape_applied_charge_c: float = 0.0 fixed_escape_correction_c: float = 0.0 fixed_current_correction_c: float = 0.0
[ドキュメント] @dataclass(frozen=True) class FieldReconstructionReceipt: """Resolved simulator settings required to reconstruct its electric field.""" schema_version: int resolved_field_solver: str fmm_expansion_order: int field_bc_mode: str tree_theta: float tree_leaf_max: int external_e0_v_m: tuple[float, float, float] use_box: bool box_min_m: tuple[float, float, float] box_max_m: tuple[float, float, float] boundary_low: tuple[int, int, int] boundary_high: tuple[int, int, int] periodic_image_layers: int periodic_far_correction: str periodic_nonzero_mode_backend: str periodic_zero_mode_policy: str periodic_lower_boundary_model: str periodic_reference_mode_layers: int periodic_panel_quadrature_order: int periodic_ewald_alpha: float periodic_ewald_layers: int periodic_cache_dir: str periodic_generation_tolerance: float # Additive v2 receipt fields; absent in released 3.0.0 outputs (supported indefinitely). upper_fourier_switch_active: bool = False upper_fourier_switch_height_m: float = 0.0 upper_fourier_switch_mode_layers: int = 0
[ドキュメント] def as_legacy_sim_mapping(self) -> dict[str, object]: """Return the combined simulator mapping consumed by field utilities.""" sim: dict[str, object] = { "field_solver": self.resolved_field_solver, "field_bc_mode": self.field_bc_mode, "tree_theta": self.tree_theta, "tree_leaf_max": self.tree_leaf_max, "e0": self.external_e0_v_m, "field_periodic_image_layers": self.periodic_image_layers, "field_periodic_far_correction": self.periodic_far_correction, "field_periodic_ewald_alpha": self.periodic_ewald_alpha, "field_periodic_ewald_layers": self.periodic_ewald_layers, "field_periodic_cache_dir": self.periodic_cache_dir, "field_periodic_generation_tolerance": ( self.periodic_generation_tolerance ), } if self.use_box: sim["box_min"] = self.box_min_m sim["box_max"] = self.box_max_m for axis, name in enumerate(("x", "y", "z")): sim[f"bc_{name}_low"] = ( "periodic" if self.boundary_low[axis] == 2 else "open" ) sim[f"bc_{name}_high"] = ( "periodic" if self.boundary_high[axis] == 2 else "open" ) return sim
[ドキュメント] @dataclass(frozen=True) class MatchingPlaneState: """One accepted quasistatic matching-plane coupling receipt.""" displacement_c_m2: float phi_v: float electron_inward_flux_m2_s: float ion_inward_flux_m2_s: float electron_access_potential_v: float ion_access_potential_v: float photoelectron_barrier_potential_v: float photoelectron_outward_flux_m2_s: float photoelectron_mean_normal_energy_ev: float electron_outward_flux_m2_s: float ion_outward_flux_m2_s: float photoelectron_return_flux_m2_s: float photoelectron_escape_flux_m2_s: float iterations: int residual: float secondary_share: float = 0.0 secondary_budget_residual_a_m2: float = 0.0 top_sheath_field_v_m: float | None = None top_cell_mean_field_v_m: float | None = None
[ドキュメント] @dataclass(frozen=True) class MatchingPlaneHistoryEntry: """Matching-plane receipt selected by ``output.history_stride``.""" batch: int simulated_time_s: float state: MatchingPlaneState
[ドキュメント] @dataclass(frozen=True) class SecondaryEmissionHistoryEntry: """Rank-summed SEE diagnostics for one incident species and accepted batch.""" batch: int incident_species: str hits: int emitted_count: int emitted_charge_c: float mean_yield: float generation_capped_count: int
[ドキュメント] @dataclass(frozen=True) class RunSummary: """Core counts and accepted simulation time from ``summary.txt``.""" mesh_nelem: int processed_particles: int absorbed: int escaped: int batches: int escaped_boundary: int = 0 survived_max_step: int = 0 last_rel_change: float = 0.0 simulated_time_s: float | None = None
[ドキュメント] @dataclass(frozen=True) class RunMesh: """Saved geometry, per-element mesh ids, materials, and centroid potentials. Missing optional CSV products are represented by ``None``. Coordinates are in meters and ``mesh_potential_v`` is in volts. """ triangles: np.ndarray | None = None mesh_ids: np.ndarray | None = None mesh_sources: dict[int, MeshSource] | None = None mesh_potential_v: np.ndarray | None = None
[ドキュメント] @dataclass(frozen=True) class RunHistory: """Lazy per-element charge and potential histories, absent files as ``None``.""" charge: BatchHistory | None = None potential: BatchHistory | None = None
[ドキュメント] @dataclass(frozen=True) class RunReceipts: """Persisted model identity and settings needed for field reconstruction.""" checkpoint_schema_version: int | None = None model_fingerprint: str | None = None mesh_fingerprint: str | None = None species_fingerprint: str | None = None field_reconstruction: FieldReconstructionReceipt | None = None matching_plane_state: MatchingPlaneState | None = None
[ドキュメント] @dataclass(frozen=True) class RunField: """Saved field source model and native-kernel identifier.""" source_model: str = "triangle_p0" kernel_id: str | None = None
[ドキュメント] @dataclass(frozen=True) class RunDiagnostics: """Optional cache, boundary retry, ledger, and adaptive-step diagnostics.""" charge_ledger_residual_c: float | None = None periodic2_cache_hit: bool | None = None periodic2_operator_build_count: int | None = None periodic2_cache_fingerprint: str | None = None periodic2_cache_path: str | None = None periodic2_generation_tolerance: float | None = None multiple_box_events_retry_attempted: int = 0 multiple_box_events_retry_resolved: int = 0 multiple_box_events_soft_discarded: int = 0 multiple_box_events_soft_discarded_abs_charge_c: float = 0.0 multiple_box_events_soft_discard_fraction: float = 0.0 adaptive_nonzero_mode_rejected_trials: int = 0 adaptive_nonzero_mode_last_batch_duration_s: float | None = None adaptive_nonzero_mode_last_potential_step_v: float | None = None adaptive_nonzero_mode_omp_threads: int | None = None periodic2_max_nonzero_mode_potential_step_v: float | None = None
[ドキュメント] @dataclass(frozen=True) class TopReferenceHistoryEntry: """One z-high plane potential sample; mismatch fields were added after 3.0.""" batch: int simulated_time_s: float z_high_m: float sample_n: int potential_mean_v: float potential_std_v: float potential_min_v: float potential_max_v: float switch_phi_rms_mismatch_v: float = 0.0 switch_ez_rms_mismatch_v_m: float = 0.0
[ドキュメント] @dataclass(frozen=True) class MatchingPlaneSpectrumHistoryEntry: """One nonempty outward photoelectron energy bin at an accepted batch.""" batch: int simulated_time_s: float bin: int energy_low_ev: float energy_high_ev: float photoelectron_outward_flux_m2_s: float
[ドキュメント] @dataclass(frozen=True) class FixedCurrentHistoryEntry: """Tracked and target charge over a history window for one species/channel. ``target_over_tracked`` is NaN when the tracked charge is zero, as written by the simulator. This diagnostic does not participate in restart state. """ batch: int simulated_time_s: float window_batches: int species_idx: int channel: str tracked_charge_c: float target_charge_c: float target_over_tracked: float
[ドキュメント] @dataclass(frozen=True) class RunResult: """Saved output from one BEACH run, grouped by purpose (light: CSV only). ``summary`` contains core counts, ``mesh`` contains saved geometry and potentials, ``history`` provides lazy :class:`BatchHistory` accessors, and ``receipts`` and ``diagnostics`` hold optional settings and monitoring data. Optional CSV files are ``None`` when absent and empty tuples when header-only. No native field kernel or matplotlib is loaded by the reader. """ directory: Path summary: RunSummary charges: np.ndarray mesh: RunMesh = dataclass_field(default_factory=RunMesh) history: RunHistory = dataclass_field(default_factory=RunHistory) receipts: RunReceipts = dataclass_field(default_factory=RunReceipts) diagnostics: RunDiagnostics = dataclass_field(default_factory=RunDiagnostics) field: RunField = dataclass_field(default_factory=RunField) ledger: tuple[ChargeLedgerEntry, ...] | None = None matching_plane_history: tuple[MatchingPlaneHistoryEntry, ...] | None = None secondary_emission_history: tuple[SecondaryEmissionHistoryEntry, ...] | None = None top_reference_history: tuple[TopReferenceHistoryEntry, ...] | None = None matching_plane_spectrum_history: tuple[MatchingPlaneSpectrumHistoryEntry, ...] | None = None fixed_current_history: tuple[FixedCurrentHistoryEntry, ...] | None = None performance_profile: tuple[dict[str, str], list[dict[str, str | float]]] | None = None
[ドキュメント] @dataclass(frozen=True) class PotentialSlice2D: """Electric potential sampled on one axis-aligned 2D slice. Attributes ---------- plane : str Plane name (``"xy"``, ``"yz"``, or ``"xz"``). axis_u : str First in-plane axis label. axis_v : str Second in-plane axis label. fixed_axis : str Axis held constant for the slice. fixed_value_m : float Fixed-axis coordinate in meters. u_values_m : numpy.ndarray Sample coordinates along ``axis_u``. v_values_m : numpy.ndarray Sample coordinates along ``axis_v``. potential_V : numpy.ndarray Potential grid in volts with shape ``(n_v, n_u)``. """ plane: str axis_u: str axis_v: str fixed_axis: str fixed_value_m: float u_values_m: np.ndarray v_values_m: np.ndarray potential_V: np.ndarray