Skip to content

aimbat.core

Core logic for AIMBAT.

All functions take a SQLModel Session and work with the models in aimbat.models. The main areas covered are:

  • Default event — get and set the default event (get_default_event, set_default_event).
  • Data — add data to the project, linking each source to its station, event, and seismogram records (add_data_to_project).
  • Events, seismograms, stations — query, update, and delete records; read and write parameters.
  • ICCS / MCCC — run the Iterative Cross-Correlation and Stack (run_iccs) and Multi-Channel Cross-Correlation (run_mccc) algorithms; update picks, time windows, and correlation thresholds.
  • Snapshots — save, restore, and delete parameter snapshots (create_snapshot, rollback_to_snapshot).
  • Project — create and delete the project database (create_project, delete_project).

Classes:

Name Description
BoundICCS

An ICCS instance explicitly bound to a specific event.

Functions:

Name Description
add_data_to_project

Add data sources to the AIMBAT database.

build_iccs_from_snapshot

Build a read-only BoundICCS from a snapshot's parameters and live waveform data.

clear_iccs_cache

Clear the process-level ICCS cache.

create_iccs_instance

Return a BoundICCS instance for the given event.

create_project

Initializes a new AIMBAT project database schema and triggers.

create_snapshot

Create a snapshot of the AIMBAT processing parameters.

delete_event

Delete an AimbatEvent from the database.

delete_event_by_id

Delete an AimbatEvent from the database by ID.

delete_project

Delete the AIMBAT project.

delete_seismogram

Delete an AimbatSeismogram from the database.

delete_seismogram_by_id

Delete an AimbatSeismogram from the database by ID.

delete_snapshot

Delete an AIMBAT parameter snapshot.

delete_snapshot_by_id

Delete an AIMBAT parameter snapshot.

delete_station

Delete an AimbatStation from the database.

delete_station_by_id

Delete an AimbatStation from the database by ID.

dump_data_table_to_json

Dump the table data to json.

dump_event_parameter_table_to_json

Dump the event parameter table data to json.

dump_event_table_to_json

Dump the table data to json.

dump_seismogram_parameter_table_to_json

Dump the seismogram parameter table data to json.

dump_seismogram_table_to_json

Create a JSON string from the AimbatSeismogram table data.

dump_snapshot_tables_to_json

Dump snapshot data as a dict of lists of dicts.

dump_station_table_to_json

Create a JSON string from the AimbatStation table data.

dump_station_table_with_counts

Dump station table with associated seismogram and event counts to a list of dicts.

get_completed_events

Get the events marked as completed.

get_data_for_event

Returns the data sources belonging to the given event.

get_default_event

Return the currently default event, or None if no event is set as default.

get_event_parameter

Get event parameter value for the given event.

get_events_using_station

Get all events that use a particular station.

get_seismogram_parameter

Get parameter value from an AimbatSeismogram instance.

get_seismogram_parameter_by_id

Get parameter value from an AimbatSeismogram by ID.

get_selected_seismograms

Get the selected seismograms for the given event.

get_snapshots

Get the snapshots for an event.

get_stations_in_event

Get the stations for a particular event.

get_stations_with_event_and_seismogram_count

Get stations along with the count of seismograms and events they are associated with.

reset_seismogram_parameters

Reset an AimbatSeismogram's parameters to their default values.

reset_seismogram_parameters_by_id

Reset an AimbatSeismogram's parameters to their default values by ID.

resolve_event

Resolve an event from either an explicit ID or the default event.

rollback_to_snapshot

Rollback to an AIMBAT parameters snapshot.

rollback_to_snapshot_by_id

Rollback to an AIMBAT parameters snapshot.

run_iccs

Run the Iterative Cross-Correlation and Stack (ICCS) algorithm.

run_mccc

Run the Multi-Channel Cross-Correlation (MCCC) algorithm.

set_default_event

Set the default event (i.e. the one being processed).

set_default_event_by_id

Set the currently selected event (i.e. the one being processed) by its ID.

set_event_parameter

Set event parameter value for the given event.

set_seismogram_parameter

Set parameter value for an AimbatSeismogram instance.

set_seismogram_parameter_by_id

Set parameter value for an AimbatSeismogram by ID.

sync_iccs_parameters

Sync an existing ICCS instance's parameters from the database.

validate_iccs_construction

Try to construct an ICCS instance for the event without caching the result.

BoundICCS dataclass

An ICCS instance explicitly bound to a specific event.

Use is_stale to detect whether the event's parameters have been modified (e.g. by a CLI command) since this instance was created.

Parameters:

Name Type Description Default
iccs ICCS
required
event_id UUID
required
created_at Timestamp
required

Methods:

Name Description
is_stale

Return True if the event has been modified since this ICCS was created.

Source code in src/aimbat/core/_iccs.py
@dataclass
class BoundICCS:
    """An ICCS instance explicitly bound to a specific event.

    Use `is_stale` to detect whether the event's parameters have been modified
    (e.g. by a CLI command) since this instance was created.
    """

    iccs: ICCS
    event_id: UUID
    created_at: Timestamp

    def is_stale(self, event: AimbatEvent) -> bool:
        """Return True if the event has been modified since this ICCS was created.

        Args:
            event: The event to check against.
        """
        if event.id != self.event_id:
            return True
        if event.last_modified is None:
            return False
        return event.last_modified > self.created_at

is_stale

is_stale(event: AimbatEvent) -> bool

Return True if the event has been modified since this ICCS was created.

Parameters:

Name Type Description Default
event AimbatEvent

The event to check against.

required
Source code in src/aimbat/core/_iccs.py
def is_stale(self, event: AimbatEvent) -> bool:
    """Return True if the event has been modified since this ICCS was created.

    Args:
        event: The event to check against.
    """
    if event.id != self.event_id:
        return True
    if event.last_modified is None:
        return False
    return event.last_modified > self.created_at

add_data_to_project

add_data_to_project(
    session: Session,
    data_sources: Sequence[str | PathLike],
    data_type: DataType,
    station_id: UUID | None = None,
    event_id: UUID | None = None,
    dry_run: bool = False,
    disable_progress_bar: bool = True,
) -> None

Add data sources to the AIMBAT database.

What gets created depends on which capabilities data_type supports:

  • Station + event + seismogram: all three records are created and linked, and an AimbatDataSource entry is stored.
  • Station or event only (e.g. JSON_STATION, JSON_EVENT): only the relevant metadata records are created; no seismogram or data source entry is stored.

Use station_id or event_id to skip extracting station or event metadata from the data source and link to a pre-existing record instead.

Parameters:

Name Type Description Default
session Session

The SQLModel database session.

required
data_sources Sequence[str | PathLike]

List of data sources to add.

required
data_type DataType

Type of data.

required
station_id UUID | None

UUID of an existing station to use instead of extracting one from each data source.

None
event_id UUID | None

UUID of an existing event to use instead of extracting one from each data source.

None
dry_run bool

If True, do not commit changes to the database.

False
disable_progress_bar bool

Do not display progress bar.

True
Source code in src/aimbat/core/_data.py
def add_data_to_project(
    session: Session,
    data_sources: Sequence[str | os.PathLike],
    data_type: DataType,
    station_id: uuid.UUID | None = None,
    event_id: uuid.UUID | None = None,
    dry_run: bool = False,
    disable_progress_bar: bool = True,
) -> None:
    """Add data sources to the AIMBAT database.

    What gets created depends on which capabilities `data_type` supports:

    - Station + event + seismogram: all three records are created and linked,
      and an `AimbatDataSource` entry is stored.
    - Station or event only (e.g. `JSON_STATION`, `JSON_EVENT`): only the
      relevant metadata records are created; no seismogram or data source entry
      is stored.

    Use `station_id` or `event_id` to skip extracting station or event metadata
    from the data source and link to a pre-existing record instead.

    Args:
        session: The SQLModel database session.
        data_sources: List of data sources to add.
        data_type: Type of data.
        station_id: UUID of an existing station to use instead of extracting
            one from each data source.
        event_id: UUID of an existing event to use instead of extracting one
            from each data source.
        dry_run: If True, do not commit changes to the database.
        disable_progress_bar: Do not display progress bar.
    """

    logger.info(f"Adding {len(data_sources)} {data_type} data sources to project.")

    if station_id is not None and session.get(AimbatStation, station_id) is None:
        raise ValueError(f"No station found with ID {station_id}.")
    if event_id is not None and session.get(AimbatEvent, event_id) is None:
        raise ValueError(f"No event found with ID {event_id}.")

    # Snapshot existing IDs before entering the savepoint so we can identify
    # what would be new vs reused when running a dry run.
    if dry_run:
        existing_station_ids = set(session.exec(select(AimbatStation.id)).all())
        existing_event_ids = set(session.exec(select(AimbatEvent.id)).all())
        existing_seismogram_ids = set(session.exec(select(AimbatSeismogram.id)).all())

    try:
        added_datasources: list[AimbatDataSource] = []
        with session.begin_nested() as nested:
            for datasource in track(
                sequence=data_sources,
                description="Adding data ...",
                disable=disable_progress_bar,
            ):
                result = _process_datasource(
                    session, datasource, data_type, station_id, event_id
                )
                if result is not None:
                    added_datasources.append(result)

            if dry_run:
                logger.info("Dry run: displaying data that would be added.")
                if added_datasources:
                    session.flush()
                    _print_dry_run_results(
                        added_datasources,
                        existing_station_ids,
                        existing_event_ids,
                        existing_seismogram_ids,
                    )
                nested.rollback()
                logger.info("Dry run complete. Rolling back changes.")
                return

        session.commit()
        logger.info("Data added successfully.")

    except Exception as e:
        logger.error(f"Failed to add data. Rolling back changes. Error: {e}")
        raise

build_iccs_from_snapshot

build_iccs_from_snapshot(
    session: Session, snapshot_id: UUID
) -> BoundICCS

Build a read-only BoundICCS from a snapshot's parameters and live waveform data.

Uses the snapshot's event and seismogram parameters (window, t1, flip, select, bandpass, etc.) but reads waveform data from the live datasources. Seismograms added after the snapshot was taken are not included in the snapshot — their live parameters are used instead. No DB writes occur at any point.

Parameters:

Name Type Description Default
session Session

Database session.

required
snapshot_id UUID

ID of the AimbatSnapshot to load.

required

Returns:

Type Description
BoundICCS

BoundICCS instance built from the snapshot parameters.

Raises:

Type Description
ValueError

If no snapshot with the given ID is found.

Source code in src/aimbat/core/_iccs.py
def build_iccs_from_snapshot(session: Session, snapshot_id: UUID) -> BoundICCS:
    """Build a read-only BoundICCS from a snapshot's parameters and live waveform data.

    Uses the snapshot's event and seismogram parameters (window, t1, flip, select,
    bandpass, etc.) but reads waveform data from the live datasources. Seismograms
    added after the snapshot was taken are not included in the snapshot — their live
    parameters are used instead. No DB writes occur at any point.

    Args:
        session: Database session.
        snapshot_id: ID of the AimbatSnapshot to load.

    Returns:
        BoundICCS instance built from the snapshot parameters.

    Raises:
        ValueError: If no snapshot with the given ID is found.
    """
    snapshot = session.get(AimbatSnapshot, snapshot_id)
    if snapshot is None:
        raise ValueError(f"Snapshot {snapshot_id} not found.")

    ep = snapshot.event_parameters_snapshot
    snap_params = AimbatEventParametersBase.model_validate(ep)

    # Build a map from seismogram_parameters_id → snapshot parameters
    snap_seis_map = {
        sp.seismogram_parameters_id: sp
        for sp in snapshot.seismogram_parameters_snapshots
    }

    seismograms = []
    for seis in snapshot.event.seismograms:
        snap_sp = snap_seis_map.get(seis.parameters.id)
        if snap_sp is None:
            # Seismogram was added after the snapshot — use live parameters
            seis_params = AimbatSeismogramParametersBase.model_validate(seis.parameters)
        else:
            seis_params = AimbatSeismogramParametersBase.model_validate(snap_sp)
        seismograms.append(
            MiniICCSSeismogram(
                begin_time=seis.begin_time,
                delta=seis.delta,
                data=seis.data,
                t0=seis.t0,
                t1=seis_params.t1,
                flip=seis_params.flip,
                select=seis_params.select,
                extra={"id": seis.id},
            )
        )

    iccs = ICCS(
        seismograms=seismograms,
        window_pre=snap_params.window_pre,
        window_post=snap_params.window_post,
        bandpass_apply=snap_params.bandpass_apply,
        bandpass_fmin=snap_params.bandpass_fmin,
        bandpass_fmax=snap_params.bandpass_fmax,
        min_ccnorm=snap_params.min_ccnorm,
        context_width=settings.context_width,
    )
    return BoundICCS(
        iccs=iccs,
        event_id=snapshot.event_id,
        created_at=Timestamp.now("UTC"),
    )

clear_iccs_cache

clear_iccs_cache() -> None

Clear the process-level ICCS cache.

Source code in src/aimbat/core/_iccs.py
def clear_iccs_cache() -> None:
    """Clear the process-level ICCS cache."""
    _iccs_cache.clear()

create_iccs_instance

create_iccs_instance(
    session: Session, event: AimbatEvent
) -> BoundICCS

Return a BoundICCS instance for the given event.

Returns the cached instance when it is still fresh (i.e. event.last_modified has not advanced since the instance was created). Otherwise builds a new one and updates the cache.

MiniICCSSeismogram instances are constructed directly from each AimbatSeismogram, passing data by reference to the read-only io cache. No waveform data is copied. The session does not need to remain open after this call.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required

Returns:

Type Description
BoundICCS

BoundICCS instance tied to the given event.

Source code in src/aimbat/core/_iccs.py
def create_iccs_instance(session: Session, event: AimbatEvent) -> BoundICCS:
    """Return a BoundICCS instance for the given event.

    Returns the cached instance when it is still fresh (i.e. `event.last_modified`
    has not advanced since the instance was created). Otherwise builds a new one
    and updates the cache.

    `MiniICCSSeismogram` instances are constructed directly from each
    `AimbatSeismogram`, passing `data` by reference to the read-only io cache.
    No waveform data is copied. The session does not need to remain open after
    this call.

    Args:
        session: Database session.
        event: AimbatEvent.

    Returns:
        BoundICCS instance tied to the given event.
    """
    cached = _iccs_cache.get(event.id)
    if cached is not None and not cached.is_stale(event):
        logger.debug(f"Returning cached BoundICCS for event {event.id}.")
        return cached

    logger.info(f"Creating ICCS instance for event {event.id}.")
    bound = BoundICCS(
        iccs=_build_iccs(event),
        event_id=event.id,
        created_at=Timestamp.now("UTC"),
    )
    _iccs_cache[event.id] = bound
    return bound

create_project

create_project(engine: Engine) -> None

Initializes a new AIMBAT project database schema and triggers.

Parameters:

Name Type Description Default
engine Engine

The SQLAlchemy/SQLModel Engine instance connected to the target database.

required

Raises:

Type Description
RuntimeError

If a project schema already exists in the target database.

Source code in src/aimbat/core/_project.py
def create_project(engine: Engine) -> None:
    """Initializes a new AIMBAT project database schema and triggers.

    Args:
        engine: The SQLAlchemy/SQLModel Engine instance connected to the target database.

    Raises:
        RuntimeError: If a project schema already exists in the target database.
    """

    # Import locally to ensure SQLModel registers all table metadata before create_all()
    import aimbat.models  # noqa: F401

    logger.info(f"Creating new project in {engine.url}")

    if _project_exists(engine):
        raise RuntimeError(
            f"Unable to create a new project: project already exists at {engine.url}!"
        )

    logger.debug("Creating database tables and loading defaults.")

    SQLModel.metadata.create_all(engine)

    if engine.name == "sqlite":
        with engine.begin() as connection:
            # Trigger 1: Handle updates to existing rows
            connection.execute(
                text("""
                CREATE TRIGGER IF NOT EXISTS single_default_event_update
                BEFORE UPDATE ON aimbatevent
                FOR EACH ROW WHEN NEW.is_default = TRUE
                BEGIN
                    UPDATE aimbatevent SET is_default = NULL 
                    WHERE is_default = TRUE AND id != NEW.id;
                END;
            """)
            )

            # Trigger 2: Handle brand new default events being inserted
            connection.execute(
                text("""
                CREATE TRIGGER IF NOT EXISTS single_default_event_insert
                BEFORE INSERT ON aimbatevent
                FOR EACH ROW WHEN NEW.is_default = TRUE
                BEGIN
                    UPDATE aimbatevent SET is_default = NULL
                    WHERE is_default = TRUE;
                END;
            """)
            )

            # Trigger 3: Track last modification time when event parameters change
            connection.execute(
                text("""
                CREATE TRIGGER IF NOT EXISTS event_modified_on_params_update
                AFTER UPDATE ON aimbateventparameters
                BEGIN
                    UPDATE aimbatevent SET last_modified = datetime('now')
                    WHERE id = NEW.event_id;
                END;
            """)
            )

            # Trigger 4: Track last modification time when seismogram parameters change
            connection.execute(
                text("""
                CREATE TRIGGER IF NOT EXISTS event_modified_on_seis_params_update
                AFTER UPDATE ON aimbatseismogramparameters
                BEGIN
                    UPDATE aimbatevent 
                    SET last_modified = strftime('%Y-%m-%d %H:%M:%f', 'now')
                    WHERE id = (
                        SELECT event_id FROM aimbatseismogram
                        WHERE id = NEW.seismogram_id
                    );
                END;
            """)
            )

create_snapshot

create_snapshot(
    session: Session,
    event: AimbatEvent,
    comment: str | None = None,
) -> None

Create a snapshot of the AIMBAT processing parameters.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required
comment str | None

Optional comment.

None
Source code in src/aimbat/core/_snapshot.py
def create_snapshot(
    session: Session, event: AimbatEvent, comment: str | None = None
) -> None:
    """Create a snapshot of the AIMBAT processing parameters.

    Args:
        session: Database session.
        event: AimbatEvent.
        comment: Optional comment.
    """

    logger.info(f"Creating snapshot for event with id={event.id} with {comment=}.")

    event_parameters_snapshot = AimbatEventParametersSnapshot.model_validate(
        event.parameters,
        update={
            "id": uuid.uuid4(),  # we don't want to carry over the id from the input event parameters
            "parameters_id": event.parameters.id,
        },
    )
    logger.debug(
        f"Adding event parameters snapshot with id={event_parameters_snapshot.id} to snapshot."
    )

    seismogram_parameter_snapshots = []
    for aimbat_seismogram in event.seismograms:
        seismogram_parameter_snapshot = AimbatSeismogramParametersSnapshot.model_validate(
            aimbat_seismogram.parameters,
            update={
                "id": uuid.uuid4(),  # we don't want to carry over the id from the input seismogram parameters
                "seismogram_parameters_id": aimbat_seismogram.parameters.id,
            },
        )
        logger.debug(
            f"Adding seismogram parameters snapshot with id={seismogram_parameter_snapshot.id} to snapshot."
        )
        seismogram_parameter_snapshots.append(seismogram_parameter_snapshot)

    aimbat_snapshot = AimbatSnapshot(
        event=event,
        event_parameters_snapshot=event_parameters_snapshot,
        seismogram_parameters_snapshots=seismogram_parameter_snapshots,
        comment=comment,
    )
    session.add(aimbat_snapshot)
    session.commit()

delete_event

delete_event(session: Session, event: AimbatEvent) -> None

Delete an AimbatEvent from the database.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

Event to delete.

required
Source code in src/aimbat/core/_event.py
def delete_event(session: Session, event: AimbatEvent) -> None:
    """Delete an AimbatEvent from the database.

    Args:
        session: Database session.
        event: Event to delete.
    """

    logger.info(f"Deleting event {event.id}.")

    session.delete(event)
    session.commit()

delete_event_by_id

delete_event_by_id(
    session: Session, event_id: UUID
) -> None

Delete an AimbatEvent from the database by ID.

Parameters:

Name Type Description Default
session Session

Database session.

required
event_id UUID

Event ID.

required

Raises:

Type Description
NoResultFound

If no AimbatEvent is found with the given ID.

Source code in src/aimbat/core/_event.py
def delete_event_by_id(session: Session, event_id: UUID) -> None:
    """Delete an AimbatEvent from the database by ID.

    Args:
        session: Database session.
        event_id: Event ID.

    Raises:
        NoResultFound: If no AimbatEvent is found with the given ID.
    """

    logger.debug(f"Getting event with id={event_id}.")

    event = session.get(AimbatEvent, event_id)
    if event is None:
        raise NoResultFound(f"Unable to find event using id: {event_id}.")
    delete_event(session, event)

delete_project

delete_project(engine: Engine) -> None

Delete the AIMBAT project.

Raises:

Type Description
RuntimeError

If unable to delete project.

Source code in src/aimbat/core/_project.py
def delete_project(engine: Engine) -> None:
    """Delete the AIMBAT project.

    Raises:
        RuntimeError: If unable to delete project.
    """

    logger.info(f"Deleting project in {engine=}.")

    if _project_exists(engine):
        if engine.driver == "pysqlite":
            database = engine.url.database
            engine.dispose()
            if database == ":memory:":
                logger.info("Running database in memory, nothing to delete.")
                return
            elif database:
                project_path = Path(database)
                logger.info(f"Deleting project file: {project_path=}")
                project_path.unlink()
                return
    raise RuntimeError("Unable to find/delete project.")

delete_seismogram

delete_seismogram(
    session: Session, seismogram: AimbatSeismogram
) -> None

Delete an AimbatSeismogram from the database.

Parameters:

Name Type Description Default
session Session

Database session.

required
seismogram AimbatSeismogram

Seismogram to delete.

required
Source code in src/aimbat/core/_seismogram.py
def delete_seismogram(session: Session, seismogram: AimbatSeismogram) -> None:
    """Delete an AimbatSeismogram from the database.

    Args:
        session: Database session.
        seismogram: Seismogram to delete.
    """

    logger.info(f"Deleting seismogram {seismogram.id}.")

    session.delete(seismogram)
    session.commit()

delete_seismogram_by_id

delete_seismogram_by_id(
    session: Session, seismogram_id: UUID
) -> None

Delete an AimbatSeismogram from the database by ID.

Parameters:

Name Type Description Default
session Session

Database session.

required
seismogram_id UUID

Seismogram ID.

required

Raises:

Type Description
NoResultFound

If no AimbatSeismogram is found with the given ID.

Source code in src/aimbat/core/_seismogram.py
def delete_seismogram_by_id(session: Session, seismogram_id: uuid.UUID) -> None:
    """Delete an AimbatSeismogram from the database by ID.

    Args:
        session: Database session.
        seismogram_id: Seismogram ID.

    Raises:
        NoResultFound: If no AimbatSeismogram is found with the given ID.
    """

    logger.debug(f"Getting seismogram with id={seismogram_id}.")

    seismogram = session.get(AimbatSeismogram, seismogram_id)
    if seismogram is None:
        raise NoResultFound(f"No AimbatSeismogram found with {seismogram_id=}")
    delete_seismogram(session, seismogram)

delete_snapshot

delete_snapshot(
    session: Session, snapshot: AimbatSnapshot
) -> None

Delete an AIMBAT parameter snapshot.

Parameters:

Name Type Description Default
session Session

Database session.

required
snapshot AimbatSnapshot

Snapshot.

required
Source code in src/aimbat/core/_snapshot.py
def delete_snapshot(session: Session, snapshot: AimbatSnapshot) -> None:
    """Delete an AIMBAT parameter snapshot.

    Args:
        session: Database session.
        snapshot: Snapshot.
    """

    logger.info(f"Deleting snapshot {snapshot.id}.")

    session.delete(snapshot)
    session.commit()

delete_snapshot_by_id

delete_snapshot_by_id(
    session: Session, snapshot_id: UUID
) -> None

Delete an AIMBAT parameter snapshot.

Parameters:

Name Type Description Default
session Session

Database session.

required
snapshot_id UUID

Snapshot id.

required
Source code in src/aimbat/core/_snapshot.py
def delete_snapshot_by_id(session: Session, snapshot_id: uuid.UUID) -> None:
    """Delete an AIMBAT parameter snapshot.

    Args:
        session: Database session.
        snapshot_id: Snapshot id.
    """

    logger.debug(f"Searching for snapshot with id {snapshot_id}.")

    snapshot = session.get(AimbatSnapshot, snapshot_id)

    if snapshot is None:
        raise ValueError(
            f"Unable to delete snapshot: snapshot with id={snapshot_id} not found."
        )

    delete_snapshot(session, snapshot)

delete_station

delete_station(
    session: Session, station: AimbatStation
) -> None

Delete an AimbatStation from the database.

Parameters:

Name Type Description Default
session Session

Database session.

required
station AimbatStation

Station to delete.

required
Source code in src/aimbat/core/_station.py
def delete_station(session: Session, station: AimbatStation) -> None:
    """Delete an AimbatStation from the database.

    Args:
        session: Database session.
        station: Station to delete.
    """

    logger.info(f"Deleting station {station.id}.")

    session.delete(station)
    session.commit()

delete_station_by_id

delete_station_by_id(
    session: Session, station_id: UUID
) -> None

Delete an AimbatStation from the database by ID.

Parameters:

Name Type Description Default
session Session

Database session.

required
station_id UUID

Station ID.

required

Raises:

Type Description
NoResultFound

If no AimbatStation is found with the given ID.

Source code in src/aimbat/core/_station.py
def delete_station_by_id(session: Session, station_id: uuid.UUID) -> None:
    """Delete an AimbatStation from the database by ID.

    Args:
        session: Database session.
        station_id: Station ID.

    Raises:
        NoResultFound: If no AimbatStation is found with the given ID.
    """

    logger.debug(f"Getting station with id={station_id}.")

    station = session.get(AimbatStation, station_id)
    if station is None:
        raise NoResultFound(f"No AimbatStation found with {station_id=}")
    delete_station(session, station)

dump_data_table_to_json

dump_data_table_to_json(session: Session) -> str

Dump the table data to json.

Source code in src/aimbat/core/_data.py
def dump_data_table_to_json(session: Session) -> str:
    """Dump the table data to json."""

    logger.info("Dumping AIMBAT datasources table to json.")

    adapter: TypeAdapter[Sequence[AimbatDataSource]] = TypeAdapter(
        Sequence[AimbatDataSource]
    )
    aimbat_datasource = session.exec(select(AimbatDataSource)).all()
    return adapter.dump_json(aimbat_datasource).decode("utf-8")

dump_event_parameter_table_to_json

dump_event_parameter_table_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | dict[str, Any] | list[dict[str, Any]]

Dump the event parameter table data to json.

Parameters:

Name Type Description Default
session Session

Database session.

required
all_events bool

Include event parameter table data for all events.

required
as_string bool

Whether to return the result as a string.

required
event AimbatEvent | None

Event to dump parameter data for (only used when all_events is False).

None
Source code in src/aimbat/core/_event.py
def dump_event_parameter_table_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | dict[str, Any] | list[dict[str, Any]]:
    """Dump the event parameter table data to json.

    Args:
        session: Database session.
        all_events: Include event parameter table data for all events.
        as_string: Whether to return the result as a string.
        event: Event to dump parameter data for (only used when all_events is False).
    """

    logger.info("Dumping AIMBAT event parameter table to json.")

    if all_events:
        adapter: TypeAdapter[Sequence[AimbatEventParameters]] = TypeAdapter(
            Sequence[AimbatEventParameters]
        )
        parameters = session.exec(select(AimbatEventParameters)).all()
        if as_string:
            return adapter.dump_json(parameters).decode("utf-8")
        else:
            return adapter.dump_python(parameters, mode="json")

    if event is None:
        raise ValueError("An event must be provided when all_events is False.")

    if as_string:
        return event.parameters.model_dump_json()
    return event.parameters.model_dump(mode="json")

dump_event_table_to_json

dump_event_table_to_json(
    session: Session, as_string: bool = True
) -> str | list[dict[str, Any]]

Dump the table data to json.

Source code in src/aimbat/core/_event.py
def dump_event_table_to_json(
    session: Session, as_string: bool = True
) -> str | list[dict[str, Any]]:
    """Dump the table data to json."""

    logger.info("Dumping AIMBAT event table to json.")
    events = session.exec(select(AimbatEvent)).all()
    event_reads = [_AimbatEventRead.from_event(e) for e in events]
    adapter: TypeAdapter[Sequence[_AimbatEventRead]] = TypeAdapter(
        Sequence[_AimbatEventRead]
    )
    if as_string:
        return adapter.dump_json(event_reads).decode("utf-8")
    return adapter.dump_python(event_reads, mode="json")

dump_seismogram_parameter_table_to_json

dump_seismogram_parameter_table_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | list[dict[str, Any]]

Dump the seismogram parameter table data to json.

Parameters:

Name Type Description Default
session Session

Database session.

required
all_events bool

Include parameters for all events.

required
as_string bool

Return as JSON string.

required
event AimbatEvent | None

Event to dump parameters for (only used when all_events is False).

None
Source code in src/aimbat/core/_seismogram.py
def dump_seismogram_parameter_table_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | list[dict[str, Any]]:
    """Dump the seismogram parameter table data to json.

    Args:
        session: Database session.
        all_events: Include parameters for all events.
        as_string: Return as JSON string.
        event: Event to dump parameters for (only used when all_events is False).
    """

    logger.info("Dumping AimbatSeismogramParameters table to json.")

    adapter: TypeAdapter[Sequence[AimbatSeismogramParameters]] = TypeAdapter(
        Sequence[AimbatSeismogramParameters]
    )

    if all_events:
        parameters = session.exec(select(AimbatSeismogramParameters)).all()
    else:
        if event is None:
            raise ValueError("An event must be provided when all_events is False.")
        parameters = session.exec(
            select(AimbatSeismogramParameters)
            .join(AimbatSeismogram)
            .where(AimbatSeismogram.event_id == event.id)
        ).all()

    if as_string:
        return adapter.dump_json(parameters).decode("utf-8")
    return adapter.dump_python(parameters, mode="json")

dump_seismogram_table_to_json

dump_seismogram_table_to_json(session: Session) -> str

Create a JSON string from the AimbatSeismogram table data.

Source code in src/aimbat/core/_seismogram.py
def dump_seismogram_table_to_json(session: Session) -> str:
    """Create a JSON string from the AimbatSeismogram table data."""

    logger.info("Dumping AIMBAT seismogram table to json.")
    adapter: TypeAdapter[Sequence[AimbatSeismogram]] = TypeAdapter(
        Sequence[AimbatSeismogram]
    )
    aimbat_seismograms = session.exec(select(AimbatSeismogram)).all()

    return adapter.dump_json(aimbat_seismograms).decode("utf-8")

dump_snapshot_tables_to_json

dump_snapshot_tables_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | dict[str, list[dict[str, Any]]]

Dump snapshot data as a dict of lists of dicts.

Returns a structure with three keys:

  • snapshots: flat list of snapshot metadata.
  • event_parameters: flat list of event parameter snapshots.
  • seismogram_parameters: flat list of seismogram parameter snapshots.

Each entry includes a snapshot_id for cross-referencing.

Parameters:

Name Type Description Default
session Session

Database session.

required
all_events bool

Include snapshots for all events.

required
as_string bool

Return a JSON string when True, otherwise a dict.

required
event AimbatEvent | None

Event to dump snapshots for (only used when all_events is False).

None
Source code in src/aimbat/core/_snapshot.py
def dump_snapshot_tables_to_json(
    session: Session,
    all_events: bool,
    as_string: bool,
    event: AimbatEvent | None = None,
) -> str | dict[str, list[dict[str, Any]]]:
    """Dump snapshot data as a dict of lists of dicts.

    Returns a structure with three keys:

    - ``snapshots``: flat list of snapshot metadata.
    - ``event_parameters``: flat list of event parameter snapshots.
    - ``seismogram_parameters``: flat list of seismogram parameter snapshots.

    Each entry includes a ``snapshot_id`` for cross-referencing.

    Args:
        session: Database session.
        all_events: Include snapshots for all events.
        as_string: Return a JSON string when True, otherwise a dict.
        event: Event to dump snapshots for (only used when all_events is False).
    """
    logger.info(f"Dumping AimbatSnapshot tables to json with {all_events=}.")

    snapshots = get_snapshots(session, event=event, all_events=all_events)

    snapshot_adapter: TypeAdapter[Sequence[_AimbatSnapshotRead]] = TypeAdapter(
        Sequence[_AimbatSnapshotRead]
    )
    event_params_adapter: TypeAdapter[Sequence[AimbatEventParametersSnapshot]] = (
        TypeAdapter(Sequence[AimbatEventParametersSnapshot])
    )
    seis_params_adapter: TypeAdapter[Sequence[AimbatSeismogramParametersSnapshot]] = (
        TypeAdapter(Sequence[AimbatSeismogramParametersSnapshot])
    )

    snapshot_reads = [_AimbatSnapshotRead.from_snapshot(s) for s in snapshots]
    event_params = [s.event_parameters_snapshot for s in snapshots]
    seis_params = [sp for s in snapshots for sp in s.seismogram_parameters_snapshots]

    data: dict[str, list[dict[str, Any]]] = {
        "snapshots": snapshot_adapter.dump_python(snapshot_reads, mode="json"),
        "event_parameters": event_params_adapter.dump_python(event_params, mode="json"),
        "seismogram_parameters": seis_params_adapter.dump_python(
            seis_params, mode="json"
        ),
    }

    return json.dumps(data) if as_string else data

dump_station_table_to_json

dump_station_table_to_json(session: Session) -> str

Create a JSON string from the AimbatStation table data.

Source code in src/aimbat/core/_station.py
def dump_station_table_to_json(session: Session) -> str:
    """Create a JSON string from the AimbatStation table data."""

    logger.info("Dumping AIMBAT station table to json.")

    adapter: TypeAdapter[Sequence[AimbatStation]] = TypeAdapter(Sequence[AimbatStation])
    aimbat_station = session.exec(select(AimbatStation)).all()
    return adapter.dump_json(aimbat_station).decode("utf-8")

dump_station_table_with_counts

dump_station_table_with_counts(
    session: Session,
) -> list[dict[str, Any]]

Dump station table with associated seismogram and event counts to a list of dicts.

Each dict represents a station and includes additional keys for the seismogram and event counts.

Parameters:

Name Type Description Default
session Session

Database session.

required

Returns: A list of dictionaries representing the stations with counts.

Source code in src/aimbat/core/_station.py
def dump_station_table_with_counts(session: Session) -> list[dict[str, Any]]:
    """Dump station table with associated seismogram and event counts to a list of dicts.

    Each dict represents a station and includes additional keys for the
    seismogram and event counts.

    Args:
        session: Database session.

    Returns: A list of dictionaries representing the stations with counts.
    """
    results = get_stations_with_event_and_seismogram_count(session)
    formatted_results = []

    for row in results:
        station_dict = row[0].model_dump(mode="json")
        station_dict["seismogram_count"] = row[1]
        station_dict["event_count"] = row[2]
        formatted_results.append(station_dict)

    return formatted_results

get_completed_events

get_completed_events(
    session: Session,
) -> Sequence[AimbatEvent]

Get the events marked as completed.

Parameters:

Name Type Description Default
session Session

SQL session.

required
Source code in src/aimbat/core/_event.py
def get_completed_events(session: Session) -> Sequence[AimbatEvent]:
    """Get the events marked as completed.

    Args:
        session: SQL session.
    """

    statement = (
        select(AimbatEvent)
        .join(AimbatEventParameters)
        .where(AimbatEventParameters.completed == 1)
    )

    return session.exec(statement).all()

get_data_for_event

get_data_for_event(
    session: Session, event: AimbatEvent
) -> Sequence[AimbatDataSource]

Returns the data sources belonging to the given event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required

Returns:

Type Description
Sequence[AimbatDataSource]

Sequence of AimbatDataSource objects belonging to the event.

Source code in src/aimbat/core/_data.py
def get_data_for_event(
    session: Session, event: AimbatEvent
) -> Sequence[AimbatDataSource]:
    """Returns the data sources belonging to the given event.

    Args:
        session: Database session.
        event: AimbatEvent.

    Returns:
        Sequence of AimbatDataSource objects belonging to the event.
    """

    logger.info(f"Getting data sources for event {event.id}.")

    statement = (
        select(AimbatDataSource)
        .join(AimbatSeismogram)
        .where(AimbatSeismogram.event_id == event.id)
    )
    return session.exec(statement).all()

get_default_event

get_default_event(session: Session) -> AimbatEvent | None

Return the currently default event, or None if no event is set as default.

Parameters:

Name Type Description Default
session Session

SQL session.

required

Returns:

Type Description
AimbatEvent | None

Default Event, or None.

Source code in src/aimbat/core/_default_event.py
def get_default_event(session: Session) -> AimbatEvent | None:
    """
    Return the currently default event, or None if no event is set as default.

    Args:
        session: SQL session.

    Returns:
        Default Event, or None.
    """

    logger.debug("Attempting to determine default event.")

    statement = select(AimbatEvent).where(AimbatEvent.is_default == 1)
    default_event = session.exec(statement).one_or_none()

    logger.debug(f"Default event: {default_event.id if default_event else None}")

    return default_event

get_event_parameter

get_event_parameter(
    session: Session,
    event: AimbatEvent,
    name: EventParameter,
) -> Timedelta | bool | float

Get event parameter value for the given event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required
name EventParameter

Name of the parameter.

required
Source code in src/aimbat/core/_event.py
def get_event_parameter(
    session: Session, event: AimbatEvent, name: EventParameter
) -> Timedelta | bool | float:
    """Get event parameter value for the given event.

    Args:
        session: Database session.
        event: AimbatEvent.
        name: Name of the parameter.
    """

    logger.info(f"Getting {name=} value for {event=}.")

    return getattr(event.parameters, name)

get_events_using_station

get_events_using_station(
    session: Session, station: AimbatStation
) -> Sequence[AimbatEvent]

Get all events that use a particular station.

Parameters:

Name Type Description Default
session Session

Database session.

required
station AimbatStation

Station to return events for.

required

Returns: Events that use the station.

Source code in src/aimbat/core/_event.py
def get_events_using_station(
    session: Session, station: AimbatStation
) -> Sequence[AimbatEvent]:
    """Get all events that use a particular station.

    Args:
        session: Database session.
        station: Station to return events for.

    Returns: Events that use the station.
    """

    logger.info(f"Getting events for station: {station.id}.")

    statement = (
        select(AimbatEvent)
        .join(AimbatSeismogram)
        .join(AimbatStation)
        .where(AimbatStation.id == station.id)
    )

    events = session.exec(statement).all()

    logger.debug(f"Found {len(events)}.")

    return events

get_seismogram_parameter

get_seismogram_parameter(
    seismogram: AimbatSeismogram, name: SeismogramParameter
) -> bool | Timestamp

Get parameter value from an AimbatSeismogram instance.

Parameters:

Name Type Description Default
seismogram AimbatSeismogram

Seismogram.

required
name SeismogramParameter

Name of the parameter value to return.

required

Returns:

Type Description
bool | Timestamp

Seismogram parameter value.

Source code in src/aimbat/core/_seismogram.py
def get_seismogram_parameter(
    seismogram: AimbatSeismogram, name: SeismogramParameter
) -> bool | Timestamp:
    """Get parameter value from an AimbatSeismogram instance.

    Args:
        seismogram: Seismogram.
        name: Name of the parameter value to return.

    Returns:
        Seismogram parameter value.
    """

    logger.info(f"Getting seismogram parameter {name=} value for {seismogram=}.")

    return getattr(seismogram.parameters, name)

get_seismogram_parameter_by_id

get_seismogram_parameter_by_id(
    session: Session,
    seismogram_id: UUID,
    name: SeismogramParameter,
) -> bool | Timestamp

Get parameter value from an AimbatSeismogram by ID.

Parameters:

Name Type Description Default
session Session

Database session.

required
seismogram_id UUID

Seismogram ID.

required
name SeismogramParameter

Name of the parameter value to return.

required

Returns:

Type Description
bool | Timestamp

Seismogram parameter value.

Raises:

Type Description
ValueError

If no AimbatSeismogram is found with the given ID.

Source code in src/aimbat/core/_seismogram.py
def get_seismogram_parameter_by_id(
    session: Session, seismogram_id: uuid.UUID, name: SeismogramParameter
) -> bool | Timestamp:
    """Get parameter value from an AimbatSeismogram by ID.

    Args:
        session: Database session.
        seismogram_id: Seismogram ID.
        name: Name of the parameter value to return.

    Returns:
        Seismogram parameter value.

    Raises:
        ValueError: If no AimbatSeismogram is found with the given ID.
    """

    logger.info(f"Getting seismogram {name=} for seismogram with id={seismogram_id}.")

    aimbat_seismogram = session.get(AimbatSeismogram, seismogram_id)

    if aimbat_seismogram is None:
        raise ValueError(f"No AimbatSeismogram found with {seismogram_id=}")

    return get_seismogram_parameter(aimbat_seismogram, name)

get_selected_seismograms

get_selected_seismograms(
    session: Session,
    event: AimbatEvent | None = None,
    all_events: bool = False,
) -> Sequence[AimbatSeismogram]

Get the selected seismograms for the given event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent | None

Event to return selected seismograms for.

None
all_events bool

Get the selected seismograms for all events.

False

Returns: Selected seismograms.

Source code in src/aimbat/core/_seismogram.py
def get_selected_seismograms(
    session: Session, event: AimbatEvent | None = None, all_events: bool = False
) -> Sequence[AimbatSeismogram]:
    """Get the selected seismograms for the given event.

    Args:
        session: Database session.
        event: Event to return selected seismograms for.
        all_events: Get the selected seismograms for all events.

    Returns: Selected seismograms.
    """

    logger.info("Getting selected AIMBAT seismograms.")

    if all_events is True:
        logger.debug("Selecting seismograms for all events.")
        statement = (
            select(AimbatSeismogram)
            .join(AimbatSeismogramParameters)
            .where(AimbatSeismogramParameters.select == 1)
        )
    else:
        if event is None:
            raise ValueError("An event must be provided when all_events is False.")
        logger.debug(f"Selecting seismograms for event {event.id} only.")
        statement = (
            select(AimbatSeismogram)
            .join(AimbatSeismogramParameters)
            .where(AimbatSeismogramParameters.select == 1)
            .where(AimbatSeismogram.event_id == event.id)
        )

    seismograms = session.exec(statement).all()

    logger.debug(f"Found {len(seismograms)} selected seismograms.")

    return seismograms

get_snapshots

get_snapshots(
    session: Session,
    event: AimbatEvent | None = None,
    all_events: bool = False,
) -> Sequence[AimbatSnapshot]

Get the snapshots for an event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent | None

Event to return snapshots for.

None
all_events bool

Get the snapshots for all events.

False

Returns: Snapshots.

Source code in src/aimbat/core/_snapshot.py
def get_snapshots(
    session: Session, event: AimbatEvent | None = None, all_events: bool = False
) -> Sequence[AimbatSnapshot]:
    """Get the snapshots for an event.

    Args:
        session: Database session.
        event: Event to return snapshots for.
        all_events: Get the snapshots for all events.

    Returns: Snapshots.
    """

    logger.info("Getting AIMBAT snapshots.")

    if all_events:
        statement = select(AimbatSnapshot)
    else:
        if event is None:
            raise ValueError("An event must be provided when all_events is False.")
        statement = select(AimbatSnapshot).where(AimbatSnapshot.event_id == event.id)

    logger.debug(f"Executing statement to get snapshots: {statement}")
    return session.exec(statement).all()

get_stations_in_event

get_stations_in_event(
    session: Session,
    event: AimbatEvent,
    as_json: bool = False,
) -> Sequence[AimbatStation] | list[dict[str, Any]]

Get the stations for a particular event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

Event to return stations for.

required
as_json bool

Whether to return the result as JSON.

False

Returns: Stations in event.

Source code in src/aimbat/core/_station.py
def get_stations_in_event(
    session: Session, event: AimbatEvent, as_json: bool = False
) -> Sequence[AimbatStation] | list[dict[str, Any]]:
    """Get the stations for a particular event.

    Args:
        session: Database session.
        event: Event to return stations for.
        as_json: Whether to return the result as JSON.

    Returns: Stations in event.
    """
    logger.info(f"Getting stations for event: {event.id}.")

    statement = (
        select(AimbatStation)
        .distinct()
        .join(AimbatSeismogram)
        .where(AimbatSeismogram.event_id == event.id)
    )

    logger.debug(f"Executing query: {statement}")
    results = session.exec(statement).all()

    if not as_json:
        return results

    adapter: TypeAdapter[Sequence[AimbatStation]] = TypeAdapter(Sequence[AimbatStation])

    return adapter.dump_python(results, mode="json")

get_stations_with_event_and_seismogram_count

get_stations_with_event_and_seismogram_count(
    session: Session,
) -> Sequence[tuple[AimbatStation, int, int]]

Get stations along with the count of seismograms and events they are associated with.

Parameters:

Name Type Description Default
session Session

Database session.

required

A sequence of tuples containing the station, count of seismograms

Type Description
Sequence[tuple[AimbatStation, int, int]]

and count of events.

Source code in src/aimbat/core/_station.py
def get_stations_with_event_and_seismogram_count(
    session: Session,
) -> Sequence[tuple[AimbatStation, int, int]]:
    """Get stations along with the count of seismograms and events they are associated with.

    Args:
        session: Database session.

    Returns: A sequence of tuples containing the station, count of seismograms
        and count of events.
    """
    logger.info("Getting stations with associated seismogram and event counts.")

    statement = (
        select(
            AimbatStation,
            func.count(col(AimbatSeismogram.id)),
            func.count(func.distinct(col(AimbatEvent.id))),
        )
        .select_from(AimbatStation)
        .join(AimbatSeismogram, isouter=True)
        .join(AimbatEvent, isouter=True)
        .group_by(col(AimbatStation.id))
    )

    logger.debug(f"Executing query: {statement}")
    return session.exec(statement).all()

reset_seismogram_parameters

reset_seismogram_parameters(
    session: Session, seismogram: AimbatSeismogram
) -> None

Reset an AimbatSeismogram's parameters to their default values.

All fields defined on AimbatSeismogramParametersBase are reset to the values produced by a fresh default instance, so newly added fields are picked up automatically.

Parameters:

Name Type Description Default
session Session

Database session.

required
seismogram AimbatSeismogram

Seismogram whose parameters should be reset.

required
Source code in src/aimbat/core/_seismogram.py
def reset_seismogram_parameters(session: Session, seismogram: AimbatSeismogram) -> None:
    """Reset an AimbatSeismogram's parameters to their default values.

    All fields defined on AimbatSeismogramParametersBase are reset to the
    values produced by a fresh default instance, so newly added fields are
    picked up automatically.

    Args:
        session: Database session.
        seismogram: Seismogram whose parameters should be reset.
    """

    logger.info(f"Resetting parameters for seismogram {seismogram.id}.")

    defaults = AimbatSeismogramParametersBase()
    for field_name in AimbatSeismogramParametersBase.model_fields:
        setattr(seismogram.parameters, field_name, getattr(defaults, field_name))
    session.add(seismogram)
    session.commit()

reset_seismogram_parameters_by_id

reset_seismogram_parameters_by_id(
    session: Session, seismogram_id: UUID
) -> None

Reset an AimbatSeismogram's parameters to their default values by ID.

Parameters:

Name Type Description Default
session Session

Database session.

required
seismogram_id UUID

Seismogram ID.

required

Raises:

Type Description
NoResultFound

If no AimbatSeismogram is found with the given ID.

Source code in src/aimbat/core/_seismogram.py
def reset_seismogram_parameters_by_id(
    session: Session, seismogram_id: uuid.UUID
) -> None:
    """Reset an AimbatSeismogram's parameters to their default values by ID.

    Args:
        session: Database session.
        seismogram_id: Seismogram ID.

    Raises:
        NoResultFound: If no AimbatSeismogram is found with the given ID.
    """

    logger.debug(f"Getting seismogram with id={seismogram_id}.")

    seismogram = session.get(AimbatSeismogram, seismogram_id)
    if seismogram is None:
        raise NoResultFound(f"No AimbatSeismogram found with {seismogram_id=}")
    reset_seismogram_parameters(session, seismogram)

resolve_event

resolve_event(
    session: Session, event_id: UUID | None = None
) -> AimbatEvent

Resolve an event from either an explicit ID or the default event.

Parameters:

Name Type Description Default
session Session

SQL session.

required
event_id UUID | None

Optional event ID.

None

Returns:

Type Description
AimbatEvent

The specified event or the default event.

Raises:

Type Description
ValueError

If an explicit event_id is given but not found.

NoResultFound

If no event_id is given and no default event is set.

Source code in src/aimbat/core/_default_event.py
def resolve_event(session: Session, event_id: UUID | None = None) -> AimbatEvent:
    """
    Resolve an event from either an explicit ID or the default event.

    Args:
        session: SQL session.
        event_id: Optional event ID.

    Returns:
        The specified event or the default event.

    Raises:
        ValueError: If an explicit event_id is given but not found.
        NoResultFound: If no event_id is given and no default event is set.
    """
    if event_id:
        logger.debug(f"Resolving event by explicit ID: {event_id}")
        event = session.get(AimbatEvent, event_id)
        if event is None:
            raise ValueError(f"No AimbatEvent found with id: {event_id}.")
        return event
    event = get_default_event(session)
    if event is None:
        raise NoResultFound("No event selected.")
    return event

rollback_to_snapshot

rollback_to_snapshot(
    session: Session, snapshot: AimbatSnapshot
) -> None

Rollback to an AIMBAT parameters snapshot.

Parameters:

Name Type Description Default
snapshot AimbatSnapshot

Snapshot.

required
Source code in src/aimbat/core/_snapshot.py
def rollback_to_snapshot(session: Session, snapshot: AimbatSnapshot) -> None:
    """Rollback to an AIMBAT parameters snapshot.

    Args:
        snapshot: Snapshot.
    """

    logger.info(f"Rolling back to snapshot with id={snapshot.id}.")

    # create object with just the parameters
    rollback_event_parameters = AimbatEventParametersBase.model_validate(
        snapshot.event_parameters_snapshot
    )
    logger.debug(
        f"Using event parameters snapshot with id={snapshot.event_parameters_snapshot.id} for rollback."
    )
    current_event_parameters = snapshot.event.parameters

    # setting attributes explicitly brings them into the session
    for k in AimbatEventParametersBase.model_fields.keys():
        v = getattr(rollback_event_parameters, k)
        logger.debug(f"Setting event parameter {k} to {v!r} for rollback.")
        setattr(current_event_parameters, k, v)

    session.add(current_event_parameters)

    for seismogram_parameters_snapshot in snapshot.seismogram_parameters_snapshots:
        rollback_seismogram_parameters = AimbatSeismogramParametersBase.model_validate(
            seismogram_parameters_snapshot
        )
        logger.debug(
            f"Using seismogram parameters snapshot with id={seismogram_parameters_snapshot.id} for rollback."
        )
        current_seismogram_parameters = seismogram_parameters_snapshot.parameters
        for k in AimbatSeismogramParametersBase.model_fields.keys():
            v = getattr(rollback_seismogram_parameters, k)
            logger.debug(f"Setting seismogram parameter {k} to {v!r} for rollback.")
            setattr(current_seismogram_parameters, k, v)
        session.add(current_seismogram_parameters)

    session.commit()

rollback_to_snapshot_by_id

rollback_to_snapshot_by_id(
    session: Session, snapshot_id: UUID
) -> None

Rollback to an AIMBAT parameters snapshot.

Parameters:

Name Type Description Default
session Session

Database session.

required
snapshot_id UUID

Snapshot id.

required
Source code in src/aimbat/core/_snapshot.py
def rollback_to_snapshot_by_id(session: Session, snapshot_id: uuid.UUID) -> None:
    """Rollback to an AIMBAT parameters snapshot.

    Args:
        session: Database session.
        snapshot_id: Snapshot id.
    """

    logger.info(f"Deleting snapshot with id={snapshot_id}.")

    snapshot = session.get(AimbatSnapshot, snapshot_id)

    if snapshot is None:
        raise ValueError(
            f"Unable to delete snapshot: snapshot with id={snapshot_id} not found."
        )

    rollback_to_snapshot(session, snapshot)

run_iccs

run_iccs(
    session: Session,
    iccs: ICCS,
    autoflip: bool,
    autoselect: bool,
) -> None

Run the Iterative Cross-Correlation and Stack (ICCS) algorithm.

Parameters:

Name Type Description Default
session Session

Database session.

required
iccs ICCS

ICCS instance.

required
autoflip bool

If True, automatically flip seismograms to maximise cross-correlation.

required
autoselect bool

If True, automatically deselect seismograms whose cross-correlation falls below the threshold.

required
Source code in src/aimbat/core/_iccs.py
def run_iccs(session: Session, iccs: ICCS, autoflip: bool, autoselect: bool) -> None:
    """Run the Iterative Cross-Correlation and Stack (ICCS) algorithm.

    Args:
        session: Database session.
        iccs: ICCS instance.
        autoflip: If True, automatically flip seismograms to maximise cross-correlation.
        autoselect: If True, automatically deselect seismograms whose cross-correlation
            falls below the threshold.
    """

    logger.info(f"Running ICCS with {autoflip=}, {autoselect=}.")

    results = iccs(autoflip=autoflip, autoselect=autoselect)
    logger.info(f"ICCS {results = }")
    _write_back_seismograms(session, iccs)

run_mccc

run_mccc(
    session: Session,
    event: AimbatEvent,
    iccs: ICCS,
    all_seismograms: bool,
) -> None

Run the Multi-Channel Cross-Correlation (MCCC) algorithm.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required
iccs ICCS

ICCS instance.

required
all_seismograms bool

If True, include deselected seismograms in the alignment.

required
Source code in src/aimbat/core/_iccs.py
def run_mccc(
    session: Session, event: AimbatEvent, iccs: ICCS, all_seismograms: bool
) -> None:
    """Run the Multi-Channel Cross-Correlation (MCCC) algorithm.

    Args:
        session: Database session.
        event: AimbatEvent.
        iccs: ICCS instance.
        all_seismograms: If True, include deselected seismograms in the alignment.
    """

    logger.info(f"Running MCCC for event {event.id} with {all_seismograms=}.")

    iccs.run_mccc(
        all_seismograms=all_seismograms,
        min_cc=event.parameters.mccc_min_ccnorm,
        damping=event.parameters.mccc_damp,
    )
    _write_back_seismograms(session, iccs)

set_default_event

set_default_event(
    session: Session, event: AimbatEvent
) -> None

Set the default event (i.e. the one being processed).

Parameters:

Name Type Description Default
session Session

SQL session.

required
event AimbatEvent

AIMBAT Event to set as default.

required
Source code in src/aimbat/core/_default_event.py
def set_default_event(session: Session, event: AimbatEvent) -> None:
    """
    Set the default event (i.e. the one being processed).

    Args:
        session: SQL session.
        event: AIMBAT Event to set as default.
    """

    logger.info(f"Setting default {event=}")

    current = get_default_event(session)
    if current is not None:
        if event.id == current.id:
            return
        current.is_default = None
        session.add(current)
        session.flush()

    event.is_default = True
    session.add(event)
    session.commit()

set_default_event_by_id

set_default_event_by_id(
    session: Session, event_id: UUID
) -> None

Set the currently selected event (i.e. the one being processed) by its ID.

Parameters:

Name Type Description Default
session Session

SQL session.

required
event_id UUID

ID of AIMBAT Event to set as default one.

required

Raises:

Type Description
ValueError

If no event with the given ID is found.

Source code in src/aimbat/core/_default_event.py
def set_default_event_by_id(session: Session, event_id: UUID) -> None:
    """
    Set the currently selected event (i.e. the one being processed) by its ID.

    Args:
        session: SQL session.
        event_id: ID of AIMBAT Event to set as default one.

    Raises:
        ValueError: If no event with the given ID is found.
    """
    logger.info(f"Setting default event to event with id={event_id}.")

    if event_id not in session.exec(select(AimbatEvent.id)).all():
        raise ValueError(f"No AimbatEvent found with id: {event_id}.")

    aimbat_event = session.exec(
        select(AimbatEvent).where(AimbatEvent.id == event_id)
    ).one()
    set_default_event(session, aimbat_event)

set_event_parameter

set_event_parameter(
    session: Session,
    event: AimbatEvent,
    name: EventParameter,
    value: Timedelta | bool | float | str,
    *,
    validate_iccs: bool = False,
) -> None

Set event parameter value for the given event.

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required
name EventParameter

Name of the parameter.

required
value Timedelta | bool | float | str

Value to set.

required
validate_iccs bool

If True, attempt ICCS construction with the new value before committing. Raises and leaves the database unchanged on failure.

False
Source code in src/aimbat/core/_event.py
def set_event_parameter(
    session: Session,
    event: AimbatEvent,
    name: EventParameter,
    value: Timedelta | bool | float | str,
    *,
    validate_iccs: bool = False,
) -> None:
    """Set event parameter value for the given event.

    Args:
        session: Database session.
        event: AimbatEvent.
        name: Name of the parameter.
        value: Value to set.
        validate_iccs: If True, attempt ICCS construction with the new value
            before committing. Raises and leaves the database unchanged on failure.
    """

    logger.info(f"Setting {name=} to {value} for {event=}.")

    parameters = AimbatEventParametersBase.model_validate(
        event.parameters, update={name: value}
    )
    new_value = getattr(parameters, name)

    if validate_iccs:
        from aimbat.core._iccs import validate_iccs_construction

        # Temporarily apply the new value in-memory with autoflush suppressed so
        # the session never writes to the DB during the validation query.
        old_value = getattr(event.parameters, name)
        with session.no_autoflush:
            setattr(event.parameters, name, new_value)
            try:
                validate_iccs_construction(event)
            except Exception as exc:
                setattr(event.parameters, name, old_value)
                raise ValueError(f"ICCS rejected {name}={value}: {exc}") from exc
            setattr(event.parameters, name, old_value)

    setattr(event.parameters, name, new_value)
    session.add(event)
    session.commit()

set_seismogram_parameter

set_seismogram_parameter(
    session: Session,
    seismogram: AimbatSeismogram,
    name: SeismogramParameter,
    value: Timestamp | bool | str,
) -> None

Set parameter value for an AimbatSeismogram instance.

Parameters:

Name Type Description Default
session Session

Database session

required
seismogram AimbatSeismogram

Seismogram to set parameter for.

required
name SeismogramParameter

Name of the parameter.

required
value Timestamp | bool | str

Value to set parameter to.

required
Source code in src/aimbat/core/_seismogram.py
def set_seismogram_parameter(
    session: Session,
    seismogram: AimbatSeismogram,
    name: SeismogramParameter,
    value: Timestamp | bool | str,
) -> None:
    """Set parameter value for an AimbatSeismogram instance.

    Args:
        session: Database session
        seismogram: Seismogram to set parameter for.
        name: Name of the parameter.
        value: Value to set parameter to.

    """

    logger.info(f"Setting seismogram {name=} to {value=} in {seismogram=}.")

    parameters = AimbatSeismogramParametersBase.model_validate(
        seismogram.parameters, update={name: value}
    )
    setattr(seismogram.parameters, name, getattr(parameters, name))
    session.add(seismogram)
    session.commit()

set_seismogram_parameter_by_id

set_seismogram_parameter_by_id(
    session: Session,
    seismogram_id: UUID,
    name: SeismogramParameter,
    value: Timestamp | bool | str,
) -> None

Set parameter value for an AimbatSeismogram by ID.

Parameters:

Name Type Description Default
session Session

Database session

required
seismogram_id UUID

Seismogram id.

required
name SeismogramParameter

Name of the parameter.

required
value Timestamp | bool | str

Value to set.

required

Raises:

Type Description
ValueError

If no AimbatSeismogram is found with the given ID.

Source code in src/aimbat/core/_seismogram.py
def set_seismogram_parameter_by_id(
    session: Session,
    seismogram_id: uuid.UUID,
    name: SeismogramParameter,
    value: Timestamp | bool | str,
) -> None:
    """Set parameter value for an AimbatSeismogram by ID.

    Args:
        session: Database session
        seismogram_id: Seismogram id.
        name: Name of the parameter.
        value: Value to set.

    Raises:
        ValueError: If no AimbatSeismogram is found with the given ID.
    """

    logger.info(
        f"Setting seismogram {name=} to {value=} for seismogram with id={seismogram_id}."
    )

    aimbat_seismogram = session.get(AimbatSeismogram, seismogram_id)

    if aimbat_seismogram is None:
        raise ValueError(f"No AimbatSeismogram found with {seismogram_id=}")

    set_seismogram_parameter(session, aimbat_seismogram, name, value)

sync_iccs_parameters

sync_iccs_parameters(
    session: Session, event: AimbatEvent, iccs: ICCS
) -> None

Sync an existing ICCS instance's parameters from the database.

Updates event-level and per-seismogram parameters without re-reading waveform data. Use this after operations that change parameters but not the seismogram list (e.g. rolling back to a snapshot).

Parameters:

Name Type Description Default
session Session

Database session.

required
event AimbatEvent

AimbatEvent.

required
iccs ICCS

ICCS instance to update in-place.

required
Source code in src/aimbat/core/_iccs.py
def sync_iccs_parameters(session: Session, event: AimbatEvent, iccs: ICCS) -> None:
    """Sync an existing ICCS instance's parameters from the database.

    Updates event-level and per-seismogram parameters without re-reading waveform
    data. Use this after operations that change parameters but not the
    seismogram list (e.g. rolling back to a snapshot).

    Args:
        session: Database session.
        event: AimbatEvent.
        iccs: ICCS instance to update in-place.
    """

    logger.info(f"Syncing ICCS parameters from database for event {event.id}.")

    event_params = AimbatEventParametersBase.model_validate(event.parameters)
    for field_name in AimbatEventParametersBase.model_fields:
        if hasattr(iccs, field_name):
            setattr(iccs, field_name, getattr(event_params, field_name))

    for iccs_seis in iccs.seismograms:
        db_seis = session.get(AimbatSeismogram, iccs_seis.extra["id"])
        if db_seis is not None:
            seis_params = AimbatSeismogramParametersBase.model_validate(
                db_seis.parameters
            )
            for field_name in AimbatSeismogramParametersBase.model_fields:
                setattr(iccs_seis, field_name, getattr(seis_params, field_name))

    iccs.clear_cache()

validate_iccs_construction

validate_iccs_construction(event: AimbatEvent) -> None

Try to construct an ICCS instance for the event without caching the result.

Use this to check whether the event's current (possibly uncommitted) parameters are compatible with ICCS construction before persisting them to the database.

Parameters:

Name Type Description Default
event AimbatEvent

AimbatEvent.

required
Source code in src/aimbat/core/_iccs.py
def validate_iccs_construction(event: AimbatEvent) -> None:
    """Try to construct an ICCS instance for the event without caching the result.

    Use this to check whether the event's current (possibly uncommitted) parameters
    are compatible with ICCS construction before persisting them to the database.

    Args:
        event: AimbatEvent.

    Raises:
        Any exception raised by ICCS construction (e.g. invalid parameter values).
    """
    _build_iccs(event)