Skip to content

aimbat.models

ORM classes mapping to AIMBAT database tables.

Each class in this module corresponds to a table in the SQLite project database and is built on SQLModel, which combines SQLAlchemy (for database access) with Pydantic (for validation).

The main classes and their relationships are:

  • AimbatEvent — a seismic event.
  • AimbatStation — a seismic recording station.
  • AimbatSeismogram — links an AimbatEvent to an AimbatStation and holds the timing metadata (begin_time, delta, t0). Waveform data is accessed via the associated AimbatDataSource.
  • AimbatDataSource — records where the waveform data for a seismogram is stored, along with its type (e.g. SAC).
  • AimbatEventParameters — processing parameters shared across all seismograms of an event (window bounds, bandpass filter settings, MCCC settings, etc.).
  • AimbatSeismogramParameters — per-seismogram processing parameters (flip, select, working pick t1).
  • AimbatSnapshot — captures a point-in-time copy of event and seismogram parameters via AimbatEventParametersSnapshot and AimbatSeismogramParametersSnapshot, enabling rollback and comparison.
  • AimbatEventQuality / AimbatSeismogramQuality — live quality metrics updated during processing; AimbatSeismogramQuality stores the ICCS cross-correlation coefficient iccs_cc and MCCC per-seismogram metrics; AimbatEventQuality stores the MCCC global RMSE.
  • AimbatEventQualitySnapshot / AimbatSeismogramQualitySnapshot — point-in-time copies of quality metrics captured alongside parameter snapshots.

Type Aliases:

Name Description
AimbatTypes

Union of all AIMBAT models that exist in the database.

Classes:

Name Description
AimbatDataSource

Class to store data source information.

AimbatEvent

Class to store seismic event information.

AimbatEventParameters

Processing parameters common to all seismograms of a particular event.

AimbatEventParametersBase

Base class defining event-level processing parameters for AIMBAT.

AimbatEventParametersSnapshot

Snapshot of processing parameters for a particular event.

AimbatEventQuality

Live quality metrics for a seismic event.

AimbatEventQualityBase

Base class defining event-level quality metrics.

AimbatEventQualitySnapshot

Snapshot of quality metrics for a seismic event.

AimbatEventRead

Read model for AimbatEvent including computed counts.

AimbatSeismogram

Class to store seismogram metadata.

AimbatSeismogramParameters

Processing parameters for a single seismogram.

AimbatSeismogramParametersBase

Base class defining seismogram-level processing parameters for AIMBAT.

AimbatSeismogramParametersSnapshot

Snapshot of processing parameters for a single seismogram.

AimbatSeismogramQuality

Live quality metrics for a single seismogram.

AimbatSeismogramQualityBase

Base class defining seismogram-level quality metrics.

AimbatSeismogramQualitySnapshot

Snapshot of quality metrics for a single seismogram.

AimbatSeismogramRead

Read model for AimbatSeismogram including parameters.

AimbatSnapshot

Container for a point-in-time snapshot of event and seismogram parameters.

AimbatSnapshotRead

Read model for AimbatSnapshot with a seismogram count.

AimbatStation

Class to store station information.

AimbatStationRead

Read model for AimbatStation including parameters.

RichColSpec

Display metadata for a model field rendered in a Rich table.

TuiColSpec

Display metadata for a model field rendered in the TUI.

AimbatDataSource

Bases: SQLModel

Class to store data source information.

Parameters:

Name Type Description Default
id UUID

Unique data source ID.

UUID('bd8793df-bf36-400c-be19-b8ae326f4c3b')
sourcename str

Path or name of the data source.

required
datatype DataType

Data type of the data source.

<DataType.SAC: 'sac'>
seismogram_id UUID

Foreign key referencing the parent seismogram.

None

Attributes:

Name Type Description
seismogram AimbatSeismogram

The seismogram this data source belongs to.

Source code in src/aimbat/models/_models.py
class AimbatDataSource(SQLModel, table=True):
    """Class to store data source information."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4,
        primary_key=True,
        title="ID",
        description="Unique data source ID.",
        schema_extra={"rich": RichColSpec(style="yellow", highlight=False)},
    )
    sourcename: str = Field(
        title="Source name",
        description="Path or name of the data source.",
    )
    datatype: DataType = Field(
        default=DataType.SAC,
        title="Data type",
        description="Data type of the data source.",
    )
    seismogram_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatseismogram.id",
        ondelete="CASCADE",
        title="Seismogram ID",
        description="Foreign key referencing the parent seismogram.",
        schema_extra={"rich": RichColSpec(style="magenta", highlight=False)},
    )
    seismogram: "AimbatSeismogram" = Relationship(back_populates="datasource")
    "The seismogram this data source belongs to."

seismogram class-attribute instance-attribute

seismogram: AimbatSeismogram = Relationship(
    back_populates="datasource"
)

The seismogram this data source belongs to.

AimbatEvent

Bases: SQLModel

Class to store seismic event information.

Parameters:

Name Type Description Default
id UUID

Generate a random UUID.

UUID('47b15b0a-127a-4653-adc9-15d6ee9b2764')
time PydanticTimestamp
required
latitude float
required
longitude float
required
depth float | None
None
last_modified PydanticTimestamp | None
None

Attributes:

Name Type Description
parameters AimbatEventParameters

Event parameters.

quality AimbatEventQuality | None

Live quality metrics for this event.

seismograms list[AimbatSeismogram]

List of seismograms of this event.

snapshots list[AimbatSnapshot]

List of snapshots.

Source code in src/aimbat/models/_models.py
class AimbatEvent(SQLModel, table=True):
    """Class to store seismic event information."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    time: PydanticTimestamp = Field(
        unique=True, sa_type=SAPandasTimestamp, allow_mutation=False
    )
    latitude: float
    longitude: float
    depth: float | None = None
    last_modified: PydanticTimestamp | None = Field(
        default=None, sa_type=SAPandasTimestamp
    )
    seismograms: list[AimbatSeismogram] = Relationship(
        back_populates="event", cascade_delete=True
    )
    "List of seismograms of this event."

    parameters: AimbatEventParameters = Relationship(
        back_populates="event", cascade_delete=True
    )
    "Event parameters."

    quality: AimbatEventQuality | None = Relationship(
        back_populates="event", cascade_delete=True
    )
    "Live quality metrics for this event."

    snapshots: list[AimbatSnapshot] = Relationship(
        back_populates="event", cascade_delete=True
    )
    "List of snapshots."

    if TYPE_CHECKING:
        # Column properties defined below, but add same default values for type checking purposes
        seismogram_count: int = 0
        station_count: int = 0
        snapshot_count: int = 0

parameters class-attribute instance-attribute

parameters: AimbatEventParameters = Relationship(
    back_populates="event", cascade_delete=True
)

Event parameters.

quality class-attribute instance-attribute

quality: AimbatEventQuality | None = Relationship(
    back_populates="event", cascade_delete=True
)

Live quality metrics for this event.

seismograms class-attribute instance-attribute

seismograms: list[AimbatSeismogram] = Relationship(
    back_populates="event", cascade_delete=True
)

List of seismograms of this event.

snapshots class-attribute instance-attribute

snapshots: list[AimbatSnapshot] = Relationship(
    back_populates="event", cascade_delete=True
)

List of snapshots.

AimbatEventParameters

Bases: AimbatEventParametersBase

Processing parameters common to all seismograms of a particular event.

Parameters:

Name Type Description Default
completed bool

Mark an event as completed.

False
ramp_width float

Width of taper ramp up and down as a fraction of the window length.

0.1
window_pre PydanticNegativeTimedelta

Pre-pick window length in seconds.

Timedelta('-1 days +23:59:45')
window_post PydanticPositiveTimedelta

Post-pick window length in seconds.

Timedelta('0 days 00:00:15')
bandpass_apply bool

Whether to apply bandpass filter to seismograms.

False
bandpass_fmin float

Minimum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

0.05
bandpass_fmax float

Maximum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

2.0
min_cc float

Minimum cross-correlation used when automatically de-selecting seismograms.

0.5
mccc_damp float

Damping factor for MCCC algorithm.

0.1
mccc_min_cc float

Minimum correlation coefficient required to include a pair in the MCCC inversion.

0.5
id UUID

Unique ID.

UUID('9a6d6322-729f-47a7-853f-2d17e4eafea4')
event_id UUID

Foreign key referencing the parent event.

None

Methods:

Name Description
check_freq_range

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

validate_iccs_context

Attempt ICCS construction with these parameters if requested.

Attributes:

Name Type Description
event AimbatEvent

The event these parameters belong to.

snapshots list[AimbatEventParametersSnapshot]

Parameter snapshots for this event.

Source code in src/aimbat/models/_models.py
class AimbatEventParameters(AimbatEventParametersBase, table=True):
    """Processing parameters common to all seismograms of a particular event."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4,
        primary_key=True,
        title="ID",
        description="Unique ID.",
        schema_extra={
            "rich": RichColSpec(style="yellow", no_wrap=True, highlight=False)
        },
    )
    event_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatevent.id",
        ondelete="CASCADE",
        title="Event ID",
        description="Foreign key referencing the parent event.",
        schema_extra={
            "rich": RichColSpec(style="magenta", no_wrap=True, highlight=False)
        },
    )
    event: "AimbatEvent" = Relationship(back_populates="parameters")
    "The event these parameters belong to."
    snapshots: list["AimbatEventParametersSnapshot"] = Relationship(
        back_populates="parameters", cascade_delete=True
    )
    "Parameter snapshots for this event."

event class-attribute instance-attribute

event: AimbatEvent = Relationship(
    back_populates="parameters"
)

The event these parameters belong to.

snapshots class-attribute instance-attribute

snapshots: list[AimbatEventParametersSnapshot] = (
    Relationship(
        back_populates="parameters", cascade_delete=True
    )
)

Parameter snapshots for this event.

check_freq_range

check_freq_range() -> Self

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def check_freq_range(self) -> Self:
    """Validate that `bandpass_fmax` is strictly greater than `bandpass_fmin`."""
    if self.bandpass_fmax <= self.bandpass_fmin:
        raise ValueError("bandpass_fmax must be > bandpass_fmin")
    return self

validate_iccs_context

validate_iccs_context(info: ValidationInfo) -> Self

Attempt ICCS construction with these parameters if requested.

Requires validate_iccs=True and an event instance in the validation context.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def validate_iccs_context(self, info: ValidationInfo) -> Self:
    """Attempt ICCS construction with these parameters if requested.

    Requires `validate_iccs=True` and an `event` instance in the validation
    context.
    """
    context = info.context or {}
    if context.get("validate_iccs"):
        event = context.get("event")
        if event:
            from aimbat.core._iccs import validate_iccs_construction

            try:
                validate_iccs_construction(event, parameters=self)
            except Exception as exc:
                raise ValueError(f"ICCS validation failed: {exc}") from exc
    return self

AimbatEventParametersBase

Bases: SQLModel

Base class defining event-level processing parameters for AIMBAT.

This class serves as a base that is inherited by the actual classes that create the database tables. The attributes correspond exactly to the AIMBAT event parameters.

Parameters:

Name Type Description Default
completed bool

Mark an event as completed.

False
ramp_width float

Width of taper ramp up and down as a fraction of the window length.

0.1
window_pre PydanticNegativeTimedelta

Pre-pick window length in seconds.

Timedelta('-1 days +23:59:45')
window_post PydanticPositiveTimedelta

Post-pick window length in seconds.

Timedelta('0 days 00:00:15')
bandpass_apply bool

Whether to apply bandpass filter to seismograms.

False
bandpass_fmin float

Minimum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

0.05
bandpass_fmax float

Maximum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

2.0
min_cc float

Minimum cross-correlation used when automatically de-selecting seismograms.

0.5
mccc_damp float

Damping factor for MCCC algorithm.

0.1
mccc_min_cc float

Minimum correlation coefficient required to include a pair in the MCCC inversion.

0.5

Methods:

Name Description
check_freq_range

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

validate_iccs_context

Attempt ICCS construction with these parameters if requested.

Source code in src/aimbat/models/_parameters.py
class AimbatEventParametersBase(SQLModel):
    """Base class defining event-level processing parameters for AIMBAT.

    This class serves as a base that is inherited by the actual classes that
    create the database tables. The attributes correspond exactly to the AIMBAT
    event parameters.
    """

    completed: bool = Field(
        default=False,
        title="Completed",
        description="Mark an event as completed.",
    )

    ramp_width: float = Field(
        default_factory=lambda: settings.ramp_width,
        title="Ramp width",
        description="Width of taper ramp up and down as a fraction of the window length.",
    )

    window_pre: PydanticNegativeTimedelta = Field(
        sa_type=SAPandasTimedelta,
        default_factory=lambda: settings.window_pre,
        title="Window pre",
        description="Pre-pick window length in seconds.",
    )

    window_post: PydanticPositiveTimedelta = Field(
        sa_type=SAPandasTimedelta,
        default_factory=lambda: settings.window_post,
        title="Window post",
        description="Post-pick window length in seconds.",
    )

    bandpass_apply: bool = Field(
        default_factory=lambda: settings.bandpass_apply,
        title="Bandpass apply",
        description="Whether to apply bandpass filter to seismograms.",
    )

    bandpass_fmin: float = Field(
        default_factory=lambda: settings.bandpass_fmin,
        ge=0,
        title="Bandpass f min",
        description="Minimum frequency for bandpass filter in Hz (ignored if `bandpass_apply` is False).",
    )

    bandpass_fmax: float = Field(
        default_factory=lambda: settings.bandpass_fmax,
        gt=0,
        title="Bandpass f max",
        description="Maximum frequency for bandpass filter in Hz (ignored if `bandpass_apply` is False).",
    )

    min_cc: float = Field(
        ge=0.0,
        le=1.0,
        default_factory=lambda: settings.min_cc,
        title="Min CC",
        description="Minimum cross-correlation used when automatically de-selecting seismograms.",
    )

    mccc_damp: float = Field(
        default_factory=lambda: settings.mccc_damp,
        ge=0,
        title="MCCC damp",
        description="Damping factor for MCCC algorithm.",
    )

    mccc_min_cc: float = Field(
        default_factory=lambda: settings.mccc_min_cc,
        ge=0,
        le=1,
        title="MCCC min CC",
        description="Minimum correlation coefficient required to include a pair in the MCCC inversion.",
    )

    @model_validator(mode="after")
    def check_freq_range(self) -> Self:
        """Validate that `bandpass_fmax` is strictly greater than `bandpass_fmin`."""
        if self.bandpass_fmax <= self.bandpass_fmin:
            raise ValueError("bandpass_fmax must be > bandpass_fmin")
        return self

    @model_validator(mode="after")
    def validate_iccs_context(self, info: ValidationInfo) -> Self:
        """Attempt ICCS construction with these parameters if requested.

        Requires `validate_iccs=True` and an `event` instance in the validation
        context.
        """
        context = info.context or {}
        if context.get("validate_iccs"):
            event = context.get("event")
            if event:
                from aimbat.core._iccs import validate_iccs_construction

                try:
                    validate_iccs_construction(event, parameters=self)
                except Exception as exc:
                    raise ValueError(f"ICCS validation failed: {exc}") from exc
        return self

check_freq_range

check_freq_range() -> Self

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def check_freq_range(self) -> Self:
    """Validate that `bandpass_fmax` is strictly greater than `bandpass_fmin`."""
    if self.bandpass_fmax <= self.bandpass_fmin:
        raise ValueError("bandpass_fmax must be > bandpass_fmin")
    return self

validate_iccs_context

validate_iccs_context(info: ValidationInfo) -> Self

Attempt ICCS construction with these parameters if requested.

Requires validate_iccs=True and an event instance in the validation context.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def validate_iccs_context(self, info: ValidationInfo) -> Self:
    """Attempt ICCS construction with these parameters if requested.

    Requires `validate_iccs=True` and an `event` instance in the validation
    context.
    """
    context = info.context or {}
    if context.get("validate_iccs"):
        event = context.get("event")
        if event:
            from aimbat.core._iccs import validate_iccs_construction

            try:
                validate_iccs_construction(event, parameters=self)
            except Exception as exc:
                raise ValueError(f"ICCS validation failed: {exc}") from exc
    return self

AimbatEventParametersSnapshot

Bases: AimbatEventParametersBase

Snapshot of processing parameters for a particular event.

Parameters:

Name Type Description Default
completed bool

Mark an event as completed.

False
ramp_width float

Width of taper ramp up and down as a fraction of the window length.

0.1
window_pre PydanticNegativeTimedelta

Pre-pick window length in seconds.

Timedelta('-1 days +23:59:45')
window_post PydanticPositiveTimedelta

Post-pick window length in seconds.

Timedelta('0 days 00:00:15')
bandpass_apply bool

Whether to apply bandpass filter to seismograms.

False
bandpass_fmin float

Minimum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

0.05
bandpass_fmax float

Maximum frequency for bandpass filter in Hz (ignored if bandpass_apply is False).

2.0
min_cc float

Minimum cross-correlation used when automatically de-selecting seismograms.

0.5
mccc_damp float

Damping factor for MCCC algorithm.

0.1
mccc_min_cc float

Minimum correlation coefficient required to include a pair in the MCCC inversion.

0.5
id UUID

Unique ID.

UUID('78e55994-ca1c-4e85-8041-05ff3a037279')
snapshot_id UUID

Foreign key referencing the parent snapshot.

None
parameters_id UUID

Foreign key referencing the source event parameters.

None

Methods:

Name Description
check_freq_range

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

validate_iccs_context

Attempt ICCS construction with these parameters if requested.

Attributes:

Name Type Description
parameters AimbatEventParameters

The event parameters this snapshot was taken from.

snapshot AimbatSnapshot

The snapshot this record belongs to.

Source code in src/aimbat/models/_models.py
class AimbatEventParametersSnapshot(AimbatEventParametersBase, table=True):
    """Snapshot of processing parameters for a particular event."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    snapshot_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatsnapshot.id",
        ondelete="CASCADE",
        title="Snapshot ID",
        description="Foreign key referencing the parent snapshot.",
    )
    parameters_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbateventparameters.id",
        ondelete="CASCADE",
        title="Event parameters ID",
        description="Foreign key referencing the source event parameters.",
    )
    snapshot: "AimbatSnapshot" = Relationship(
        back_populates="event_parameters_snapshot"
    )
    "The snapshot this record belongs to."
    parameters: AimbatEventParameters = Relationship(back_populates="snapshots")
    "The event parameters this snapshot was taken from."

parameters class-attribute instance-attribute

parameters: AimbatEventParameters = Relationship(
    back_populates="snapshots"
)

The event parameters this snapshot was taken from.

snapshot class-attribute instance-attribute

snapshot: AimbatSnapshot = Relationship(
    back_populates="event_parameters_snapshot"
)

The snapshot this record belongs to.

check_freq_range

check_freq_range() -> Self

Validate that bandpass_fmax is strictly greater than bandpass_fmin.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def check_freq_range(self) -> Self:
    """Validate that `bandpass_fmax` is strictly greater than `bandpass_fmin`."""
    if self.bandpass_fmax <= self.bandpass_fmin:
        raise ValueError("bandpass_fmax must be > bandpass_fmin")
    return self

validate_iccs_context

validate_iccs_context(info: ValidationInfo) -> Self

Attempt ICCS construction with these parameters if requested.

Requires validate_iccs=True and an event instance in the validation context.

Source code in src/aimbat/models/_parameters.py
@model_validator(mode="after")
def validate_iccs_context(self, info: ValidationInfo) -> Self:
    """Attempt ICCS construction with these parameters if requested.

    Requires `validate_iccs=True` and an `event` instance in the validation
    context.
    """
    context = info.context or {}
    if context.get("validate_iccs"):
        event = context.get("event")
        if event:
            from aimbat.core._iccs import validate_iccs_construction

            try:
                validate_iccs_construction(event, parameters=self)
            except Exception as exc:
                raise ValueError(f"ICCS validation failed: {exc}") from exc
    return self

AimbatEventQuality

Bases: AimbatEventQualityBase

Live quality metrics for a seismic event.

One row per event. Updated in place whenever MCCC runs. Fields are None until MCCC has been executed.

Parameters:

Name Type Description Default
mccc_rmse PydanticPositiveTimedelta | None

Root-mean-square error of the MCCC inversion fit across the whole array.

None
id UUID

Unique ID.

UUID('980d7d63-de83-47ee-b1b7-08bafd66c4ab')
event_id UUID

Foreign key referencing the parent event.

None

Attributes:

Name Type Description
event AimbatEvent

The event these quality metrics belong to.

snapshots list[AimbatEventQualitySnapshot]

Quality snapshots taken from this live record.

Source code in src/aimbat/models/_models.py
class AimbatEventQuality(AimbatEventQualityBase, table=True):
    """Live quality metrics for a seismic event.

    One row per event. Updated in place whenever MCCC runs.
    Fields are `None` until MCCC has been executed.
    """

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    event_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatevent.id",
        ondelete="CASCADE",
        title="Event ID",
        description="Foreign key referencing the parent event.",
    )
    event: "AimbatEvent" = Relationship(back_populates="quality")
    "The event these quality metrics belong to."
    snapshots: list["AimbatEventQualitySnapshot"] = Relationship(
        back_populates="quality", cascade_delete=True
    )
    "Quality snapshots taken from this live record."

event class-attribute instance-attribute

event: AimbatEvent = Relationship(back_populates='quality')

The event these quality metrics belong to.

snapshots class-attribute instance-attribute

snapshots: list[AimbatEventQualitySnapshot] = Relationship(
    back_populates="quality", cascade_delete=True
)

Quality snapshots taken from this live record.

AimbatEventQualityBase

Bases: SQLModel

Base class defining event-level quality metrics.

Fields are None when the corresponding algorithm has not been run yet.

Parameters:

Name Type Description Default
mccc_rmse PydanticPositiveTimedelta | None

Root-mean-square error of the MCCC inversion fit across the whole array.

None
Source code in src/aimbat/models/_quality.py
class AimbatEventQualityBase(SQLModel):
    """Base class defining event-level quality metrics.

    Fields are `None` when the corresponding algorithm has not been run yet.
    """

    mccc_rmse: PydanticPositiveTimedelta | None = Field(
        default=None,
        sa_type=SAPandasTimedelta,
        title="MCCC RMSE",
        description="Root-mean-square error of the MCCC inversion fit across the whole array.",
    )

AimbatEventQualitySnapshot

Bases: AimbatEventQualityBase

Snapshot of quality metrics for a seismic event.

Parameters:

Name Type Description Default
mccc_rmse PydanticPositiveTimedelta | None

Root-mean-square error of the MCCC inversion fit across the whole array.

None
id UUID

Unique ID.

UUID('ba8dcd59-85e0-411c-bd78-60b14a2374b1')
event_quality_id UUID

Foreign key referencing the source event quality.

None
snapshot_id UUID

Foreign key referencing the parent snapshot.

None

Attributes:

Name Type Description
quality AimbatEventQuality

The event quality this snapshot was taken from.

snapshot AimbatSnapshot

The snapshot this record belongs to.

Source code in src/aimbat/models/_models.py
class AimbatEventQualitySnapshot(AimbatEventQualityBase, table=True):
    """Snapshot of quality metrics for a seismic event."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    event_quality_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbateventquality.id",
        ondelete="CASCADE",
        title="Event quality ID",
        description="Foreign key referencing the source event quality.",
    )
    quality: AimbatEventQuality = Relationship(back_populates="snapshots")
    "The event quality this snapshot was taken from."
    snapshot_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatsnapshot.id",
        ondelete="CASCADE",
        title="Snapshot ID",
        description="Foreign key referencing the parent snapshot.",
    )
    snapshot: "AimbatSnapshot" = Relationship(back_populates="event_quality_snapshot")
    "The snapshot this record belongs to."

quality class-attribute instance-attribute

quality: AimbatEventQuality = Relationship(
    back_populates="snapshots"
)

The event quality this snapshot was taken from.

snapshot class-attribute instance-attribute

snapshot: AimbatSnapshot = Relationship(
    back_populates="event_quality_snapshot"
)

The snapshot this record belongs to.

AimbatEventRead

Bases: BaseModel

Read model for AimbatEvent including computed counts.

Parameters:

Name Type Description Default
id UUID

Unique identifier for the event

required
short_id str | None

Shortened unique identifier

None
completed bool

Indicates if the event's parameters are marked as completed

required
time PydanticTimestamp

Origin time of the event

required
latitude float

Latitude of the event

required
longitude float

Longitude of the event

required
depth float | None

Depth of the event

required
seismogram_count int

Number of seismograms associated with this event

required
station_count int

Number of stations associated with this event

required
snapshot_count int

Number of snapshots associated with this event

required
last_modified PydanticTimestamp | None

Timestamp of the last modification of this event's parameters

None

Methods:

Name Description
from_event

Create an AimbatEventRead from an AimbatEvent ORM instance.

Source code in src/aimbat/models/_readers.py
class AimbatEventRead(BaseModel):
    """Read model for AimbatEvent including computed counts."""

    model_config = ConfigDict(
        frozen=True,
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: UUID = Field(
        title="ID",
        description="Unique identifier for the event",
        json_schema_extra={
            "rich": RichColSpec(style="yellow"),  # type: ignore[dict-item]
        },
    )
    short_id: str | None = Field(
        default=None,
        title="Short ID",
        description="Shortened unique identifier",
        json_schema_extra={
            "tui": TuiColSpec(display_title="ID"),  # type: ignore[dict-item]
            "rich": RichColSpec(display_title="ID", style="yellow", highlight=False),  # type: ignore[dict-item]
        },
    )
    completed: bool = Field(
        title="Completed",
        description="Indicates if the event's parameters are marked as completed",
        json_schema_extra={"tui": TuiColSpec(text_align="center")},  # type: ignore[dict-item]
    )
    time: PydanticTimestamp = Field(
        title="Event time",
        description="Origin time of the event",
    )
    latitude: float = Field(
        title="Latitude",
        description="Latitude of the event",
    )
    longitude: float = Field(
        title="Longitude",
        description="Longitude of the event",
    )
    depth: float | None = Field(
        title="Depth",
        description="Depth of the event",
        json_schema_extra={
            "tui": TuiColSpec(display_title="Depth km", formatter=fmt_depth_km),  # type: ignore[dict-item]
            "rich": RichColSpec(
                display_title=r"Depth \[km]", justify="right", formatter=fmt_depth_km
            ),  # type: ignore[dict-item]
        },
    )
    seismogram_count: int = Field(
        title="Seismograms",
        description="Number of seismograms associated with this event",
    )
    station_count: int = Field(
        title="Stations",
        description="Number of stations associated with this event",
    )
    snapshot_count: int = Field(
        title="Snapshots",
        description="Number of snapshots associated with this event",
    )
    last_modified: PydanticTimestamp | None = Field(
        default=None,
        title="Last modified",
        description="Timestamp of the last modification of this event's parameters",
    )

    @classmethod
    def from_event(cls, event: "AimbatEvent", session: "Session | None" = None) -> Self:
        """Create an AimbatEventRead from an AimbatEvent ORM instance."""
        data = event.model_dump()

        if session is not None:
            from aimbat.utils import uuid_shortener

            data["short_id"] = uuid_shortener(session, event)

        data.update(
            {
                "completed": event.parameters.completed if event.parameters else False,
                "seismogram_count": event.seismogram_count or 0,
                "station_count": event.station_count or 0,
                "snapshot_count": event.snapshot_count or 0,
            }
        )
        return cls(**data)

from_event classmethod

from_event(
    event: AimbatEvent, session: Session | None = None
) -> Self

Create an AimbatEventRead from an AimbatEvent ORM instance.

Source code in src/aimbat/models/_readers.py
@classmethod
def from_event(cls, event: "AimbatEvent", session: "Session | None" = None) -> Self:
    """Create an AimbatEventRead from an AimbatEvent ORM instance."""
    data = event.model_dump()

    if session is not None:
        from aimbat.utils import uuid_shortener

        data["short_id"] = uuid_shortener(session, event)

    data.update(
        {
            "completed": event.parameters.completed if event.parameters else False,
            "seismogram_count": event.seismogram_count or 0,
            "station_count": event.station_count or 0,
            "snapshot_count": event.snapshot_count or 0,
        }
    )
    return cls(**data)

AimbatSeismogram

Bases: SQLModel

Class to store seismogram metadata.

Parameters:

Name Type Description Default
id UUID

Generate a random UUID.

UUID('e1d61588-8131-4408-b24a-8e9bf5ef689d')
begin_time PydanticTimestamp

Start time of the seismogram.

required
delta PydanticPositiveTimedelta

Sampling interval.

required
t0 PydanticTimestamp

Initial phase arrival pick.

required
station_id UUID

Foreign key referencing the recording station.

None
event_id UUID

Foreign key referencing the parent event.

None
extra dict[Hashable, Any]

Dictionary to store any additional metadata for the seismogram.

<class 'dict'>

Methods:

Name Description
end_time

End time of the seismogram, derived from begin_time, delta, and data length.

Attributes:

Name Type Description
data NDArray[float64]

Seismogram waveform data array.

datasource AimbatDataSource

Data source for the seismogram waveform.

event AimbatEvent

The event this seismogram belongs to.

flip bool

Whether the seismogram should be flipped.

parameters AimbatSeismogramParameters

Processing parameters for this seismogram.

quality AimbatSeismogramQuality | None

Live quality metrics for this seismogram.

select bool

Whether this seismogram should be used for processing.

station AimbatStation

The station that recorded this seismogram.

t1 Timestamp | None

Working phase arrival pick.

Source code in src/aimbat/models/_models.py
class AimbatSeismogram(SQLModel, table=True):
    """Class to store seismogram metadata."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    begin_time: PydanticTimestamp = Field(
        sa_type=SAPandasTimestamp,
        title="Begin time",
        description="Start time of the seismogram.",
    )
    delta: PydanticPositiveTimedelta = Field(
        sa_type=SAPandasTimedelta,
        title="Sampling interval",
        description="Sampling interval.",
    )
    t0: PydanticTimestamp = Field(
        sa_type=SAPandasTimestamp,
        title="Initial pick",
        description="Initial phase arrival pick.",
    )
    datasource: AimbatDataSource = Relationship(
        back_populates="seismogram", cascade_delete=True
    )
    "Data source for the seismogram waveform."
    station_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatstation.id",
        ondelete="CASCADE",
        title="Station ID",
        description="Foreign key referencing the recording station.",
    )
    station: "AimbatStation" = Relationship(back_populates="seismograms")
    "The station that recorded this seismogram."
    event_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatevent.id",
        ondelete="CASCADE",
        title="Event ID",
        description="Foreign key referencing the parent event.",
    )
    extra: dict[Hashable, Any] = Field(
        default_factory=dict,
        sa_column=Column(MutableDict.as_mutable(PickleType)),
        title="Extra metadata",
        description="Dictionary to store any additional metadata for the seismogram.",
    )
    event: "AimbatEvent" = Relationship(back_populates="seismograms")
    "The event this seismogram belongs to."
    parameters: "AimbatSeismogramParameters" = Relationship(
        back_populates="seismogram",
        cascade_delete=True,
    )
    "Processing parameters for this seismogram."
    quality: AimbatSeismogramQuality | None = Relationship(
        back_populates="seismogram",
        cascade_delete=True,
    )
    "Live quality metrics for this seismogram."

    if TYPE_CHECKING:
        # Add same default values for type checking purposes
        # as in AimbatSeismogramParametersBase
        flip: bool = False
        select: bool = True
        t1: Timestamp | None = None
        data: npt.NDArray[np.float64] = np.array([])

        @property
        def end_time(self) -> Timestamp: ...

    else:

        @computed_field
        def end_time(self) -> PydanticTimestamp:
            """End time of the seismogram, derived from begin_time, delta, and data length."""
            if len(self.data) == 0:
                return self.begin_time
            return self.begin_time + self.delta * (len(self.data) - 1)

        @property
        def flip(self) -> bool:
            """Whether the seismogram should be flipped."""
            return self.parameters.flip

        @flip.setter
        def flip(self, value: bool) -> None:
            self.parameters.flip = value

        @property
        def select(self) -> bool:
            """Whether this seismogram should be used for processing."""
            return self.parameters.select

        @select.setter
        def select(self, value: bool) -> None:
            self.parameters.select = value

        @property
        def t1(self) -> Timestamp | None:
            """Working phase arrival pick."""
            return self.parameters.t1

        @t1.setter
        def t1(self, value: Timestamp | None) -> None:
            self.parameters.t1 = value

        @property
        def data(self) -> npt.NDArray[np.float64]:
            """Seismogram waveform data array."""
            if self.datasource is None:
                raise ValueError("Expected a valid datasource name, got None.")
            return read_seismogram_data(
                self.datasource.sourcename, self.datasource.datatype
            )

        @data.setter
        def data(self, value: npt.NDArray[np.float64]) -> None:
            if self.datasource is None:
                raise ValueError("Expected a valid datasource name, got None.")
            write_seismogram_data(
                self.datasource.sourcename, self.datasource.datatype, value
            )

data property writable

Seismogram waveform data array.

datasource class-attribute instance-attribute

datasource: AimbatDataSource = Relationship(
    back_populates="seismogram", cascade_delete=True
)

Data source for the seismogram waveform.

event class-attribute instance-attribute

event: AimbatEvent = Relationship(
    back_populates="seismograms"
)

The event this seismogram belongs to.

flip property writable

flip: bool

Whether the seismogram should be flipped.

parameters class-attribute instance-attribute

parameters: AimbatSeismogramParameters = Relationship(
    back_populates="seismogram", cascade_delete=True
)

Processing parameters for this seismogram.

quality class-attribute instance-attribute

quality: AimbatSeismogramQuality | None = Relationship(
    back_populates="seismogram", cascade_delete=True
)

Live quality metrics for this seismogram.

select property writable

select: bool

Whether this seismogram should be used for processing.

station class-attribute instance-attribute

station: AimbatStation = Relationship(
    back_populates="seismograms"
)

The station that recorded this seismogram.

t1 property writable

t1: Timestamp | None

Working phase arrival pick.

end_time

end_time() -> PydanticTimestamp

End time of the seismogram, derived from begin_time, delta, and data length.

Source code in src/aimbat/models/_models.py
@computed_field
def end_time(self) -> PydanticTimestamp:
    """End time of the seismogram, derived from begin_time, delta, and data length."""
    if len(self.data) == 0:
        return self.begin_time
    return self.begin_time + self.delta * (len(self.data) - 1)

AimbatSeismogramParameters

Bases: AimbatSeismogramParametersBase

Processing parameters for a single seismogram.

Parameters:

Name Type Description Default
flip bool

Whether or not the seismogram should be flipped.

False
select bool

Whether or not this seismogram should be used for processing.

True
t1 PydanticTimestamp | None

Working pick. This pick serves as working as well as output pick. It is changed by: 1. Picking the phase arrival in the stack, 2. Running ICCS, 3. Running MCCC.

None
id UUID

Unique ID.

UUID('579ae189-ee8e-4287-bcbd-a2b28ff04ae8')
seismogram_id UUID

Foreign key referencing the parent seismogram.

None

Attributes:

Name Type Description
seismogram AimbatSeismogram

The seismogram these parameters belong to.

snapshots list[AimbatSeismogramParametersSnapshot]

Parameter snapshots for this seismogram.

Source code in src/aimbat/models/_models.py
class AimbatSeismogramParameters(AimbatSeismogramParametersBase, table=True):
    """Processing parameters for a single seismogram."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4,
        primary_key=True,
        title="ID",
        description="Unique ID.",
    )
    seismogram_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatseismogram.id",
        ondelete="CASCADE",
        title="Seismogram ID",
        description="Foreign key referencing the parent seismogram.",
    )

    seismogram: "AimbatSeismogram" = Relationship(back_populates="parameters")
    "The seismogram these parameters belong to."

    snapshots: list["AimbatSeismogramParametersSnapshot"] = Relationship(
        back_populates="parameters", cascade_delete=True
    )
    "Parameter snapshots for this seismogram."

seismogram class-attribute instance-attribute

seismogram: AimbatSeismogram = Relationship(
    back_populates="parameters"
)

The seismogram these parameters belong to.

snapshots class-attribute instance-attribute

snapshots: list[AimbatSeismogramParametersSnapshot] = (
    Relationship(
        back_populates="parameters", cascade_delete=True
    )
)

Parameter snapshots for this seismogram.

AimbatSeismogramParametersBase

Bases: SQLModel

Base class defining seismogram-level processing parameters for AIMBAT.

Parameters:

Name Type Description Default
flip bool

Whether or not the seismogram should be flipped.

False
select bool

Whether or not this seismogram should be used for processing.

True
t1 PydanticTimestamp | None

Working pick. This pick serves as working as well as output pick. It is changed by: 1. Picking the phase arrival in the stack, 2. Running ICCS, 3. Running MCCC.

None
Source code in src/aimbat/models/_parameters.py
class AimbatSeismogramParametersBase(SQLModel):
    """Base class defining seismogram-level processing parameters for AIMBAT."""

    flip: bool = Field(
        default=False,
        title="Flip",
        description="Whether or not the seismogram should be flipped.",
    )

    select: bool = Field(
        default=True,
        title="Select",
        description="Whether or not this seismogram should be used for processing.",
    )

    t1: PydanticTimestamp | None = Field(
        default=None,
        sa_type=SAPandasTimestamp,
        title="T1",
        description=(
            "Working pick. This pick serves as working as well as output pick."
            " It is changed by: 1. Picking the phase arrival in the stack,"
            " 2. Running ICCS, 3. Running MCCC."
        ),
    )

AimbatSeismogramParametersSnapshot

Bases: AimbatSeismogramParametersBase

Snapshot of processing parameters for a single seismogram.

Parameters:

Name Type Description Default
flip bool

Whether or not the seismogram should be flipped.

False
select bool

Whether or not this seismogram should be used for processing.

True
t1 PydanticTimestamp | None

Working pick. This pick serves as working as well as output pick. It is changed by: 1. Picking the phase arrival in the stack, 2. Running ICCS, 3. Running MCCC.

None
id UUID

Unique ID.

UUID('6b461c01-e113-4d17-a369-4adec9ca5456')
seismogram_parameters_id UUID

Foreign key referencing the source seismogram parameters.

required
snapshot_id UUID

Foreign key referencing the parent snapshot.

None

Attributes:

Name Type Description
parameters AimbatSeismogramParameters

The seismogram parameters this snapshot was taken from.

snapshot AimbatSnapshot

The snapshot this record belongs to.

Source code in src/aimbat/models/_models.py
class AimbatSeismogramParametersSnapshot(AimbatSeismogramParametersBase, table=True):
    """Snapshot of processing parameters for a single seismogram."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    seismogram_parameters_id: uuid.UUID = Field(
        foreign_key="aimbatseismogramparameters.id",
        ondelete="CASCADE",
        title="Seismogram parameters ID",
        description="Foreign key referencing the source seismogram parameters.",
    )
    parameters: AimbatSeismogramParameters = Relationship(back_populates="snapshots")
    "The seismogram parameters this snapshot was taken from."
    snapshot_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatsnapshot.id",
        ondelete="CASCADE",
        title="Snapshot ID",
        description="Foreign key referencing the parent snapshot.",
    )
    snapshot: "AimbatSnapshot" = Relationship(
        back_populates="seismogram_parameters_snapshots"
    )
    "The snapshot this record belongs to."

parameters class-attribute instance-attribute

parameters: AimbatSeismogramParameters = Relationship(
    back_populates="snapshots"
)

The seismogram parameters this snapshot was taken from.

snapshot class-attribute instance-attribute

snapshot: AimbatSnapshot = Relationship(
    back_populates="seismogram_parameters_snapshots"
)

The snapshot this record belongs to.

AimbatSeismogramQuality

Bases: AimbatSeismogramQualityBase

Live quality metrics for a single seismogram.

One row per seismogram. Updated in place whenever ICCS or MCCC runs. Fields are None until the corresponding algorithm has been executed.

Parameters:

Name Type Description Default
iccs_cc float | None

Pearson cross-correlation coefficient of this seismogram with the ICCS stack.

None
mccc_cc_mean float | None

Mean cross-correlation coefficient from the MCCC run (waveform quality).

None
mccc_cc_std float | None

Standard deviation of cross-correlation coefficients from the MCCC run (waveform consistency).

None
mccc_error PydanticPositiveTimedelta | None

Timing precision (standard error from covariance matrix) from the MCCC run.

None
id UUID

Unique ID.

UUID('98af3f86-c98b-4782-adb1-d21f5c6cc9e2')
seismogram_id UUID

Foreign key referencing the parent seismogram.

None

Attributes:

Name Type Description
seismogram AimbatSeismogram

The seismogram these quality metrics belong to.

snapshots list[AimbatSeismogramQualitySnapshot]

Quality snapshots taken from this live record.

Source code in src/aimbat/models/_models.py
class AimbatSeismogramQuality(AimbatSeismogramQualityBase, table=True):
    """Live quality metrics for a single seismogram.

    One row per seismogram. Updated in place whenever ICCS or MCCC runs.
    Fields are `None` until the corresponding algorithm has been executed.
    """

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    seismogram_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatseismogram.id",
        ondelete="CASCADE",
        title="Seismogram ID",
        description="Foreign key referencing the parent seismogram.",
    )
    seismogram: "AimbatSeismogram" = Relationship(back_populates="quality")
    "The seismogram these quality metrics belong to."
    snapshots: list["AimbatSeismogramQualitySnapshot"] = Relationship(
        back_populates="quality", cascade_delete=True
    )
    "Quality snapshots taken from this live record."

seismogram class-attribute instance-attribute

seismogram: AimbatSeismogram = Relationship(
    back_populates="quality"
)

The seismogram these quality metrics belong to.

snapshots class-attribute instance-attribute

snapshots: list[AimbatSeismogramQualitySnapshot] = (
    Relationship(
        back_populates="quality", cascade_delete=True
    )
)

Quality snapshots taken from this live record.

AimbatSeismogramQualityBase

Bases: SQLModel

Base class defining seismogram-level quality metrics.

Fields are None when the corresponding algorithm has not been run for this seismogram.

Parameters:

Name Type Description Default
iccs_cc float | None

Pearson cross-correlation coefficient of this seismogram with the ICCS stack.

None
mccc_cc_mean float | None

Mean cross-correlation coefficient from the MCCC run (waveform quality).

None
mccc_cc_std float | None

Standard deviation of cross-correlation coefficients from the MCCC run (waveform consistency).

None
mccc_error PydanticPositiveTimedelta | None

Timing precision (standard error from covariance matrix) from the MCCC run.

None
Source code in src/aimbat/models/_quality.py
class AimbatSeismogramQualityBase(SQLModel):
    """Base class defining seismogram-level quality metrics.

    Fields are `None` when the corresponding algorithm has not been run for
    this seismogram.
    """

    iccs_cc: float | None = Field(
        default=None,
        ge=-1.0,
        le=1.0,
        title="ICCS CC",
        description="Pearson cross-correlation coefficient of this seismogram with the ICCS stack.",
    )

    mccc_cc_mean: float | None = Field(
        default=None,
        ge=0.0,
        le=1.0,
        title="MCCC CC mean",
        description="Mean cross-correlation coefficient from the MCCC run (waveform quality).",
    )

    mccc_cc_std: float | None = Field(
        default=None,
        ge=0.0,
        title="MCCC CC std",
        description="Standard deviation of cross-correlation coefficients from the MCCC run (waveform consistency).",
    )

    mccc_error: PydanticPositiveTimedelta | None = Field(
        default=None,
        sa_type=SAPandasTimedelta,
        title="MCCC error",
        description="Timing precision (standard error from covariance matrix) from the MCCC run.",
    )

AimbatSeismogramQualitySnapshot

Bases: AimbatSeismogramQualityBase

Snapshot of quality metrics for a single seismogram.

Parameters:

Name Type Description Default
iccs_cc float | None

Pearson cross-correlation coefficient of this seismogram with the ICCS stack.

None
mccc_cc_mean float | None

Mean cross-correlation coefficient from the MCCC run (waveform quality).

None
mccc_cc_std float | None

Standard deviation of cross-correlation coefficients from the MCCC run (waveform consistency).

None
mccc_error PydanticPositiveTimedelta | None

Timing precision (standard error from covariance matrix) from the MCCC run.

None
id UUID

Unique ID.

UUID('0b775346-0fb5-4212-902c-2387b4a52f2e')
seismogram_quality_id UUID

Foreign key referencing the source seismogram quality.

None
snapshot_id UUID

Foreign key referencing the parent snapshot.

None

Attributes:

Name Type Description
quality AimbatSeismogramQuality

The seismogram quality this snapshot was taken from.

snapshot AimbatSnapshot

The snapshot this record belongs to.

Source code in src/aimbat/models/_models.py
class AimbatSeismogramQualitySnapshot(AimbatSeismogramQualityBase, table=True):
    """Snapshot of quality metrics for a single seismogram."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    seismogram_quality_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatseismogramquality.id",
        ondelete="CASCADE",
        title="Seismogram quality ID",
        description="Foreign key referencing the source seismogram quality.",
    )
    quality: AimbatSeismogramQuality = Relationship(back_populates="snapshots")
    "The seismogram quality this snapshot was taken from."
    snapshot_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatsnapshot.id",
        ondelete="CASCADE",
        title="Snapshot ID",
        description="Foreign key referencing the parent snapshot.",
    )
    snapshot: "AimbatSnapshot" = Relationship(
        back_populates="seismogram_quality_snapshots"
    )
    "The snapshot this record belongs to."

quality class-attribute instance-attribute

quality: AimbatSeismogramQuality = Relationship(
    back_populates="snapshots"
)

The seismogram quality this snapshot was taken from.

snapshot class-attribute instance-attribute

snapshot: AimbatSnapshot = Relationship(
    back_populates="seismogram_quality_snapshots"
)

The snapshot this record belongs to.

AimbatSeismogramRead

Bases: BaseModel

Read model for AimbatSeismogram including parameters.

Parameters:

Name Type Description Default
id UUID

Unique identifier for the seismogram

required
short_id str | None

Shortened unique identifier

None
name str

Name of the seismogram.

required
channel str

Seismogram channel.

required
select bool

Whether the seismogram is selected for processing.

required
flip bool

Whether the seismogram is flipped for processing.

required
delta_t PydanticTimedelta | None

Arrival time residual (observed - predicted) in seconds.

required
mccc_error PydanticTimedelta | None

Uncertainty in the MCCC arrival time residual (observed - predicted) in seconds.

required
iccs_cc float | None

Cross-correlation coefficient with ICCS stack.

required
mccc_cc_mean float | None

Mean cross-correlation coefficient of MCCC cluster.

required
mccc_cc_std float | None

Standard deviation of cross-correlation coefficients in MCCC cluster.

required
event_id UUID

ID of the associated event.

required
short_event_id str | None

Shortened unique identifier for the associated event.

required
Source code in src/aimbat/models/_readers.py
class AimbatSeismogramRead(BaseModel):
    """Read model for AimbatSeismogram including parameters."""

    model_config = ConfigDict(
        frozen=True,
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: UUID = Field(
        title="ID",
        description="Unique identifier for the seismogram",
        json_schema_extra={
            "rich": RichColSpec(style="yellow", no_wrap=True, highlight=False),  # type: ignore[dict-item]
        },
    )
    short_id: str | None = Field(
        default=None,
        title="Short ID",
        description="Shortened unique identifier",
        json_schema_extra={
            "tui": TuiColSpec(display_title="ID"),  # type: ignore[dict-item]
            "rich": RichColSpec(
                display_title="ID", style="yellow", no_wrap=True, highlight=False
            ),  # type: ignore[dict-item]
        },
    )
    name: str = Field(title="Name", description="Name of the seismogram.")

    channel: str = Field(
        title="Channel",
        description="Seismogram channel.",
    )

    select: bool = Field(
        title="Select",
        description="Whether the seismogram is selected for processing.",
        json_schema_extra={"tui": TuiColSpec(text_align="center")},  # type: ignore[dict-item]
    )

    flip: bool = Field(
        title="Flip",
        description="Whether the seismogram is flipped for processing.",
        json_schema_extra={
            "tui": TuiColSpec(text_align="center", formatter=fmt_flip),  # type: ignore[dict-item]
            "rich": RichColSpec(formatter=fmt_flip),  # type: ignore[dict-item]
        },
    )

    delta_t: PydanticTimedelta | None = Field(
        title="Δt (s)",
        description="Arrival time residual (observed - predicted) in seconds.",
    )

    mccc_error: PydanticTimedelta | None = Field(
        title="MCCC err Δt (s)",
        description="Uncertainty in the MCCC arrival time residual (observed - predicted) in seconds.",
    )

    iccs_cc: float | None = Field(
        title="Stack CC",
        description="Cross-correlation coefficient with ICCS stack.",
    )

    mccc_cc_mean: float | None = Field(
        title="MCCC CC",
        description="Mean cross-correlation coefficient of MCCC cluster.",
    )

    mccc_cc_std: float | None = Field(
        title="MCCC CC std",
        description="Standard deviation of cross-correlation coefficients in MCCC cluster.",
    )

    event_id: UUID = Field(
        title="Event ID",
        description="ID of the associated event.",
        json_schema_extra={
            "rich": RichColSpec(style="magenta", no_wrap=True, highlight=False),  # type: ignore[dict-item]
        },
    )

    short_event_id: str | None = Field(
        title="Short Event ID",
        description="Shortened unique identifier for the associated event.",
        json_schema_extra={
            "rich": RichColSpec(
                display_title="Event ID", style="magenta", no_wrap=True, highlight=False
            ),  # type: ignore[dict-item]
        },
    )

    @classmethod
    def from_seismogram(
        cls, seismogram: "AimbatSeismogram", session: "Session | None" = None
    ) -> Self:
        name = (f"{seismogram.station.network}." or "") + seismogram.station.name

        short_id = None
        short_event_id = None
        if session is not None:
            from aimbat.utils import uuid_shortener

            short_id = uuid_shortener(session, seismogram)
            short_event_id = uuid_shortener(session, seismogram.event)

        delta_t = (
            seismogram.parameters.t1 - seismogram.t0
            if seismogram.parameters.t1
            else None
        )
        return cls(
            id=seismogram.id,
            short_id=short_id,
            name=name,
            channel=seismogram.station.channel,
            select=seismogram.parameters.select,
            flip=seismogram.parameters.flip,
            delta_t=delta_t,
            mccc_error=getattr(seismogram.quality, "mccc_error", None),
            iccs_cc=getattr(seismogram.quality, "iccs_cc", None),
            mccc_cc_mean=getattr(seismogram.quality, "mccc_cc_mean", None),
            mccc_cc_std=getattr(seismogram.quality, "mccc_cc_std", None),
            event_id=seismogram.event_id,
            short_event_id=short_event_id,
        )

AimbatSnapshot

Bases: SQLModel

Container for a point-in-time snapshot of event and seismogram parameters.

The AimbatSnapshot class does not actually save any parameter data. It is used to keep track of the AimbatEventParametersSnapshot and AimbatSeismogramParametersSnapshot instances.

Parameters:

Name Type Description Default
id UUID

Unique ID.

UUID('82070ebe-fb08-4304-8a3b-786d52a72bc4')
time PydanticTimestamp

Timestamp when the snapshot was created.

Timestamp('2026-03-19 12:09:10.117143+0000', tz='UTC')
comment str | None

Optional comment for the snapshot.

None
parameters_hash str | None

SHA-256 hash of event and seismogram parameters at creation time.

None
event_id UUID

Foreign key referencing the parent event.

None

Attributes:

Name Type Description
event AimbatEvent

The event this snapshot belongs to.

event_parameters_snapshot AimbatEventParametersSnapshot

Event parameter snapshot associated with this snapshot.

event_quality_snapshot AimbatEventQualitySnapshot | None

Event quality metric snapshot associated with this snapshot.

seismogram_parameters_snapshots list[AimbatSeismogramParametersSnapshot]

Seismogram parameter snapshots associated with this snapshot.

seismogram_quality_snapshots list[AimbatSeismogramQualitySnapshot]

Seismogram quality metric snapshots associated with this snapshot.

Source code in src/aimbat/models/_models.py
class AimbatSnapshot(SQLModel, table=True):
    """Container for a point-in-time snapshot of event and seismogram parameters.

    The AimbatSnapshot class does not actually save any parameter data.
    It is used to keep track of the AimbatEventParametersSnapshot and
    AimbatSeismogramParametersSnapshot instances.
    """

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(
        default_factory=uuid.uuid4, primary_key=True, description="Unique ID."
    )
    time: PydanticTimestamp = Field(
        default_factory=lambda: Timestamp.now(tz=timezone.utc),
        unique=True,
        allow_mutation=False,
        sa_type=SAPandasTimestamp,
        title="Snapshot time",
        description="Timestamp when the snapshot was created.",
    )
    comment: str | None = Field(
        default=None, description="Optional comment for the snapshot."
    )
    parameters_hash: str | None = Field(
        default=None,
        title="Hash",
        description="SHA-256 hash of event and seismogram parameters at creation time.",
    )
    event_parameters_snapshot: AimbatEventParametersSnapshot = Relationship(
        back_populates="snapshot", cascade_delete=True
    )
    "Event parameter snapshot associated with this snapshot."
    seismogram_parameters_snapshots: list[AimbatSeismogramParametersSnapshot] = (
        Relationship(back_populates="snapshot", cascade_delete=True)
    )
    "Seismogram parameter snapshots associated with this snapshot."
    event_quality_snapshot: AimbatEventQualitySnapshot | None = Relationship(
        back_populates="snapshot", cascade_delete=True
    )
    "Event quality metric snapshot associated with this snapshot."
    seismogram_quality_snapshots: list[AimbatSeismogramQualitySnapshot] = Relationship(
        back_populates="snapshot", cascade_delete=True
    )
    "Seismogram quality metric snapshots associated with this snapshot."
    event_id: uuid.UUID = Field(
        default=None,
        foreign_key="aimbatevent.id",
        ondelete="CASCADE",
        title="Event ID",
        description="Foreign key referencing the parent event.",
    )
    event: "AimbatEvent" = Relationship(back_populates="snapshots")
    "The event this snapshot belongs to."

    if TYPE_CHECKING:
        # defined as column properties below, but add same default values for type checking purposes
        seismogram_count: int = 0
        selected_seismogram_count: int = 0
        flipped_seismogram_count: int = 0

event class-attribute instance-attribute

event: AimbatEvent = Relationship(
    back_populates="snapshots"
)

The event this snapshot belongs to.

event_parameters_snapshot class-attribute instance-attribute

event_parameters_snapshot: AimbatEventParametersSnapshot = (
    Relationship(
        back_populates="snapshot", cascade_delete=True
    )
)

Event parameter snapshot associated with this snapshot.

event_quality_snapshot class-attribute instance-attribute

event_quality_snapshot: (
    AimbatEventQualitySnapshot | None
) = Relationship(
    back_populates="snapshot", cascade_delete=True
)

Event quality metric snapshot associated with this snapshot.

seismogram_parameters_snapshots class-attribute instance-attribute

seismogram_parameters_snapshots: list[
    AimbatSeismogramParametersSnapshot
] = Relationship(
    back_populates="snapshot", cascade_delete=True
)

Seismogram parameter snapshots associated with this snapshot.

seismogram_quality_snapshots class-attribute instance-attribute

seismogram_quality_snapshots: list[
    AimbatSeismogramQualitySnapshot
] = Relationship(
    back_populates="snapshot", cascade_delete=True
)

Seismogram quality metric snapshots associated with this snapshot.

AimbatSnapshotRead

Bases: BaseModel

Read model for AimbatSnapshot with a seismogram count.

Parameters:

Name Type Description Default
id UUID

Unique identifier for the snapshot

required
short_id str | None

Shortened unique identifier

None
time PydanticTimestamp

Timestamp of the snapshot

required
comment str | None

Optional comment for the snapshot

required
seismogram_count int

Total number of seismograms in the snapshot

required
selected_seismogram_count int

Number of selected seismograms in the snapshot

required
flipped_seismogram_count int

Number of flipped seismograms in the snapshot

required
cc_mean float | None

Mean cross-correlation coefficient for this snapshot

None
cc_sem float | None

Standard error of the mean of cross-correlation coefficients for this snapshot

None
mccc bool | None

Whether MCCC parameters are included in this snapshot

None
event_id UUID

ID of the associated event

required
short_event_id str | None

Shortened unique identifier for the associated event

required

Methods:

Name Description
from_snapshot

Create an AimbatSnapshotRead from an AimbatSnapshot ORM instance.

Source code in src/aimbat/models/_readers.py
class AimbatSnapshotRead(BaseModel):
    """Read model for AimbatSnapshot with a seismogram count."""

    model_config = ConfigDict(
        frozen=True,
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: UUID = Field(
        title="ID",
        description="Unique identifier for the snapshot",
        json_schema_extra={
            "rich": RichColSpec(style="yellow", no_wrap=True, highlight=False),  # type: ignore[dict-item]
        },
    )
    short_id: str | None = Field(
        default=None,
        title="Short ID",
        description="Shortened unique identifier",
        json_schema_extra={
            "tui": TuiColSpec(display_title="ID"),  # type: ignore[dict-item]
            "rich": RichColSpec(
                display_title="ID", style="yellow", no_wrap=True, highlight=False
            ),  # type: ignore[dict-item]
        },
    )
    time: PydanticTimestamp = Field(
        title="Time", description="Timestamp of the snapshot"
    )
    comment: str | None = Field(
        title="Comment", description="Optional comment for the snapshot"
    )
    seismogram_count: int = Field(
        title="Seismograms",
        description="Total number of seismograms in the snapshot",
    )
    selected_seismogram_count: int = Field(
        title="Selected",
        description="Number of selected seismograms in the snapshot",
    )
    flipped_seismogram_count: int = Field(
        title="Flipped",
        description="Number of flipped seismograms in the snapshot",
    )

    cc_mean: float | None = Field(
        default=None,
        title="Stack CC (mean)",
        description="Mean cross-correlation coefficient for this snapshot",
    )

    cc_sem: float | None = Field(
        default=None,
        title="Stack CC (SEM)",
        description="Standard error of the mean of cross-correlation coefficients for this snapshot",
    )

    mccc: bool | None = Field(
        default=None,
        title="MCCC",
        description="Whether MCCC parameters are included in this snapshot",
    )

    event_id: UUID = Field(
        title="Event ID",
        description="ID of the associated event",
        json_schema_extra={
            "rich": RichColSpec(style="magenta", no_wrap=True, highlight=False),  # type: ignore[dict-item]
        },
    )
    short_event_id: str | None = Field(
        title="Short Event ID",
        description="Shortened unique identifier for the associated event",
        json_schema_extra={
            "rich": RichColSpec(
                display_title="Event ID", style="magenta", no_wrap=True, highlight=False
            ),  # type: ignore[dict-item]
        },
    )

    @classmethod
    def from_snapshot(
        cls, snapshot: "AimbatSnapshot", session: "Session | None" = None
    ) -> Self:
        """Create an AimbatSnapshotRead from an AimbatSnapshot ORM instance."""

        short_id = None
        short_event_id = None
        if session is not None:
            from aimbat.utils import uuid_shortener

            short_id = uuid_shortener(session, snapshot)
            short_event_id = uuid_shortener(session, snapshot.event)

        iccs_ccs = [
            q.iccs_cc
            for q in snapshot.seismogram_quality_snapshots
            if q.iccs_cc is not None
        ]
        cc_mean, cc_sem = mean_and_sem(iccs_ccs)
        mccc = bool(snapshot.event_quality_snapshot)

        return cls(
            id=snapshot.id,
            short_id=short_id,
            time=snapshot.time,
            comment=snapshot.comment,
            seismogram_count=snapshot.seismogram_count,
            selected_seismogram_count=snapshot.selected_seismogram_count,
            flipped_seismogram_count=snapshot.flipped_seismogram_count,
            cc_mean=cc_mean,
            cc_sem=cc_sem,
            mccc=mccc,
            event_id=snapshot.event_id,
            short_event_id=short_event_id,
        )

from_snapshot classmethod

from_snapshot(
    snapshot: AimbatSnapshot, session: Session | None = None
) -> Self

Create an AimbatSnapshotRead from an AimbatSnapshot ORM instance.

Source code in src/aimbat/models/_readers.py
@classmethod
def from_snapshot(
    cls, snapshot: "AimbatSnapshot", session: "Session | None" = None
) -> Self:
    """Create an AimbatSnapshotRead from an AimbatSnapshot ORM instance."""

    short_id = None
    short_event_id = None
    if session is not None:
        from aimbat.utils import uuid_shortener

        short_id = uuid_shortener(session, snapshot)
        short_event_id = uuid_shortener(session, snapshot.event)

    iccs_ccs = [
        q.iccs_cc
        for q in snapshot.seismogram_quality_snapshots
        if q.iccs_cc is not None
    ]
    cc_mean, cc_sem = mean_and_sem(iccs_ccs)
    mccc = bool(snapshot.event_quality_snapshot)

    return cls(
        id=snapshot.id,
        short_id=short_id,
        time=snapshot.time,
        comment=snapshot.comment,
        seismogram_count=snapshot.seismogram_count,
        selected_seismogram_count=snapshot.selected_seismogram_count,
        flipped_seismogram_count=snapshot.flipped_seismogram_count,
        cc_mean=cc_mean,
        cc_sem=cc_sem,
        mccc=mccc,
        event_id=snapshot.event_id,
        short_event_id=short_event_id,
    )

AimbatStation

Bases: SQLModel

Class to store station information.

Parameters:

Name Type Description Default
id UUID

Generate a random UUID.

UUID('f66b55dd-8004-4b40-94a3-cf8970c93801')
name str
required
network str
required
location str
required
channel str
required
latitude float
required
longitude float
required
elevation float | None
None

Attributes:

Name Type Description
seismograms list[AimbatSeismogram]

Seismograms recorded at this station.

Source code in src/aimbat/models/_models.py
class AimbatStation(SQLModel, table=True):
    """Class to store station information."""

    model_config = SQLModelConfig(
        alias_generator=to_camel,
        populate_by_name=True,
    )

    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    name: str = Field(allow_mutation=False)
    network: str = Field(allow_mutation=False)
    location: str = Field(allow_mutation=False)
    channel: str = Field(allow_mutation=False)
    latitude: float
    longitude: float
    elevation: float | None = None
    seismograms: list[AimbatSeismogram] = Relationship(
        back_populates="station", cascade_delete=True
    )
    "Seismograms recorded at this station."

    if TYPE_CHECKING:
        # Column properties defined below, but add same default values for type checking purposes
        seismogram_count: int = 0
        event_count: int = 0

seismograms class-attribute instance-attribute

seismograms: list[AimbatSeismogram] = Relationship(
    back_populates="station", cascade_delete=True
)

Seismograms recorded at this station.

AimbatStationRead

Bases: BaseModel

Read model for AimbatStation including parameters.

Parameters:

Name Type Description Default
id UUID

Unique identifier for the station

required
short_id str | None

Shortened unique identifier

None
network str

Station network code

required
name str

Station name

required
location str | None

Station location code

required
channel str

Station channel code

required
latitude float

Station latitude

required
longitude float

Station longitude

required
elevation float | None

Station elevation

None
cc_mean float | None

Mean cross-correlation coefficient at this station

None
cc_sem float | None

Standard error of the mean of cross-correlation coefficients at this station

None
seismogram_count int

Number of seismograms associated with this station

required
event_count int

Number of unique events recorded at this station

required
Source code in src/aimbat/models/_readers.py
class AimbatStationRead(BaseModel):
    """Read model for AimbatStation including parameters."""

    model_config = ConfigDict(
        frozen=True, alias_generator=to_camel, populate_by_name=True
    )

    id: UUID = Field(
        title="ID",
        description="Unique identifier for the station",
        json_schema_extra={
            "rich": RichColSpec(style="yellow", no_wrap=True, highlight=False),  # type: ignore[dict-item]
        },
    )
    short_id: str | None = Field(
        default=None,
        title="Short ID",
        description="Shortened unique identifier",
        json_schema_extra={
            "tui": TuiColSpec(display_title="ID"),  # type: ignore[dict-item]
            "rich": RichColSpec(
                display_title="ID", style="yellow", no_wrap=True, highlight=False
            ),  # type: ignore[dict-item]
        },
    )
    network: str = Field(title="Network", description="Station network code")
    name: str = Field(title="Name", description="Station name")
    location: str | None = Field(title="Location", description="Station location code")
    channel: str = Field(title="Channel", description="Station channel code")
    latitude: float = Field(title="Latitude", description="Station latitude")
    longitude: float = Field(title="Longitude", description="Station longitude")
    elevation: float | None = Field(
        default=None,
        title="Elevation",
        description="Station elevation",
        json_schema_extra={"tui": TuiColSpec(formatter=lambda x: str(int(x)))},  # type: ignore[dict-item]
    )

    cc_mean: float | None = Field(
        default=None,
        title="Stack CC (mean)",
        description="Mean cross-correlation coefficient at this station",
    )

    cc_sem: float | None = Field(
        default=None,
        title="Stack CC (SEM)",
        description="Standard error of the mean of cross-correlation coefficients at this station",
    )

    seismogram_count: int = Field(
        title="Seismogram count",
        description="Number of seismograms associated with this station",
    )

    event_count: int = Field(
        title="Event count",
        description="Number of unique events recorded at this station",
    )

    @classmethod
    def from_station(
        cls,
        station: "AimbatStation",
        session: "Session | None" = None,
    ) -> Self:
        data = station.model_dump()

        if session is not None:
            from aimbat.utils import uuid_shortener

            data["short_id"] = uuid_shortener(session, station)
            iccs_ccs = tuple(
                seis.quality.iccs_cc
                for seis in station.seismograms
                if seis.quality is not None and seis.quality.iccs_cc is not None
            )
            data["cc_mean"], data["cc_sem"] = mean_and_sem(iccs_ccs)

        data.update(
            {
                "seismogram_count": station.seismogram_count or 0,
                "event_count": station.event_count or 0,
            }
        )
        return cls(**data)

RichColSpec

Bases: BaseModel

Display metadata for a model field rendered in a Rich table.

Attach to a field via json_schema_extra={"rich": RichColSpec(...)}. Only attributes that differ from the field's defaults need to be set.

Attributes:

Name Type Description

Parameters:

Name Type Description Default
display_title str | None
None
justify Literal['left', 'center', 'right'] | None
None
style str | None
None
no_wrap bool | None
None
highlight bool | None
True
formatter Callable[list, str] | None
None
Source code in src/aimbat/models/_format.py
class RichColSpec(BaseModel):
    """Display metadata for a model field rendered in a Rich table.

    Attach to a field via `json_schema_extra={"rich": RichColSpec(...)}`.
    Only attributes that differ from the field's defaults need to be set.

    Attributes:
        display_title: Override for the column header shown in the Rich table.
            If `None`, the field's `title` is used instead.
        justify: Horizontal alignment for cell values in this column.
            Maps to `rich.table.Column.justify`. If `None`, no explicit
            alignment is applied.
        style: Style string for the column (e.g. "bold magenta").
        no_wrap: If `True`, cell values in this column will not wrap.
        highlight: If `True`, enables Rich's automatic syntax highlighting for
            values in this column. If `False`, disables it. If `None`, no
            explicit setting is applied.
        formatter: Custom formatter for cell values. Called with the raw field
            value (guaranteed non-`None`) and must return a display string. If
            `None`, a generic fallback is used instead.
    """

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

    display_title: str | None = None
    justify: Literal["left", "center", "right"] | None = None
    style: str | None = None
    no_wrap: bool | None = None
    highlight: bool | None = True
    formatter: Callable[[Any], str] | None = None

TuiColSpec dataclass

Display metadata for a model field rendered in the TUI.

Attach to a field via json_schema_extra={"tui": TuiColSpec(...)}. Only attributes that differ from the field's defaults need to be set.

Attributes:

Name Type Description

Parameters:

Name Type Description Default
display_title str | None
None
text_align Literal['left', 'center', 'right'] | None
None
formatter Formatter[Any] | None
None
Source code in src/aimbat/models/_format.py
@dataclass(frozen=True)
class TuiColSpec:
    """Display metadata for a model field rendered in the TUI.

    Attach to a field via `json_schema_extra={"tui": TuiColSpec(...)}`.
    Only attributes that differ from the field's defaults need to be set.

    Attributes:
        display_title: Override for the column header shown in the TUI table.
            If `None`, the field's `title` is used instead.
        text_align: Horizontal alignment for cell values in this column.
            Maps to `rich.text.Text.justify`. If `None`, no explicit alignment
            is applied and the DataTable renders with its default (left).
        formatter: Custom formatter for cell values. Called with the raw field
            value (guaranteed non-`None`) and must return a display string. If
            `None`, the generic `tui_fmt` fallback is used instead.
    """

    display_title: str | None = None
    text_align: Literal["left", "center", "right"] | None = None
    formatter: Formatter[Any] | None = None