Skip to content

aimbat.core

Business logic for AIMBAT processing operations.

All functions accept a SQLModel Session and operate on the ORM models in aimbat.models. The main areas of functionality are:

  • Active event — get and set the active event (get_active_event, set_active_event). Only one event is processed at a time; switching clears the seismogram data cache.
  • Data ingestion — add data sources to the project, linking each to its station, event, and seismogram records (add_data_to_project).
  • Events, seismograms, stations — query, update, and delete records; read and write processing 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 — create, restore, and delete parameter snapshots for rollback and comparison (create_snapshot, rollback_to_snapshot).
  • Project — create and delete the project database (create_project, delete_project).

Functions:

Name Description
add_data_to_project

Add data sources to the AIMBAT database.

create_iccs_instance

Create an ICCS instance for the active 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.

get_active_event

Return the currently active event (i.e. the one being processed).

get_completed_events

Get the events marked as completed.

get_data_for_active_event

Returns the data sources belonging to the active event.

get_event_parameter

Get event parameter value for the active 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 active avent.

get_snapshots

Get the snapshots for the active avent.

get_stations_in_active_event

Get the stations for the active event.

get_stations_in_event

Get the stations for a particular event.

get_stations_with_event_seismogram_count

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

plot_all_seismograms

Plot all seismograms for a particular event ordered by great circle distance.

plot_iccs_seismograms

Plot the ICCS seismograms as an image.

plot_stack

Plot the ICCS stack.

print_data_table

Print a pretty table with information about the data sources in the database.

print_event_parameter_table

Print a pretty table with AIMBAT parameter values for the active event.

print_event_table

Print a pretty table with AIMBAT events.

print_project_info

Show AIMBAT project information.

print_seismogram_parameter_table

Print a pretty table with AIMBAT seismogram parameter values for the active event.

print_seismogram_table

Prints a pretty table with AIMBAT seismograms.

print_snapshot_table

Print a pretty table with AIMBAT snapshots.

print_station_table

Prints a pretty table with AIMBAT stations.

rollback_to_snapshot

Rollback to an AIMBAT parameters snapshot.

rollback_to_snapshot_by_id

Rollback to an AIMBAT parameters snapshot.

run_iccs

Run ICCS algorithm.

run_mccc

Run MCCC algorithm.

set_active_event

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

set_active_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 active event.

set_seismogram_parameter

Set parameter value for an AimbatSeismogram instance.

set_seismogram_parameter_by_id

Set parameter value for an AimbatSeismogram by ID.

update_min_ccnorm

Update the minimum cross correlation coefficient for the active event.

update_pick

Update the pick for the active event.

update_timewindow

Update the time window for the active event.

add_data_to_project

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

Add data sources to the AIMBAT database.

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
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,
    dry_run: bool = False,
    disable_progress_bar: bool = True,
) -> None:
    """Add data sources to the AIMBAT database.

    Args:
        session: The SQLModel database session.
        data_sources: List of data sources to add.
        data_type: Type of data.
        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.")

    # 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,
            ):
                added_datasources.append(
                    _add_datasource(session, datasource, data_type)
                )

            if dry_run:
                logger.info("Dry run: displaying data that would be added.")
                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

create_iccs_instance

create_iccs_instance(session: Session) -> ICCS

Create an ICCS instance for the active event.

Parameters:

Name Type Description Default
session Session

Database session.

required

Returns:

Type Description
ICCS

ICCS instance.

Source code in src/aimbat/core/_iccs.py
def create_iccs_instance(session: Session) -> ICCS:
    """Create an ICCS instance for the active event.

    Args:
        session: Database session.

    Returns:
        ICCS instance.
    """

    logger.info("Creating ICCS instance for active event.")

    active_event = get_active_event(session)

    return ICCS(
        seismograms=active_event.seismograms,
        window_pre=active_event.parameters.window_pre,
        window_post=active_event.parameters.window_post,
        bandpass_apply=active_event.parameters.bandpass_apply,
        bandpass_fmin=active_event.parameters.bandpass_fmin,
        bandpass_fmax=active_event.parameters.bandpass_fmax,
        min_ccnorm=active_event.parameters.min_ccnorm,
        context_width=settings.context_width,
    )

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_active_event_update
                BEFORE UPDATE ON aimbatevent
                FOR EACH ROW WHEN NEW.active = TRUE
                BEGIN
                    UPDATE aimbatevent SET active = NULL 
                    WHERE active = TRUE AND id != NEW.id;
                END;
            """))

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

create_snapshot

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

Create a snapshot of the AIMBAT processing parameters.

Parameters:

Name Type Description Default
session Session

Database session.

required
comment str | None

Optional comment.

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

    Args:
        session: Database session.
        comment: Optional comment.
    """
    active_aimbat_event = get_active_event(session)

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

    event_parameters_snapshot = AimbatEventParametersSnapshot.model_validate(
        active_aimbat_event.parameters,
        update={
            "id": uuid.uuid4(),  # we don't want to carry over the id from the active parameters
            "parameters_id": active_aimbat_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 active_aimbat_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 active 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=active_aimbat_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}. {HINTS.LIST_EVENTS}"
        )
    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
) -> str | dict[str, Any] | list[dict[str, Any]]

Dump the event parameter table data to json.

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

    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")

    active_event = get_active_event(session)

    if as_string:
        return active_event.parameters.model_dump_json()
    return active_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
) -> str | list[dict[str, Any]]

Dump the seismogram parameter table data to json.

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

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

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

    if all_events:
        parameters = session.exec(select(AimbatSeismogramParameters)).all()
    else:
        parameters = session.exec(
            select(AimbatSeismogramParameters)
            .join(AimbatSeismogram)
            .join(AimbatEvent)
            .where(AimbatEvent.active == 1)
        ).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
) -> 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
Source code in src/aimbat/core/_snapshot.py
def dump_snapshot_tables_to_json(
    session: Session, all_events: bool, as_string: bool
) -> 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.
    """
    logger.info(f"Dumping AimbatSnapshot tables to json with {all_events=}.")

    snapshots = get_snapshots(session, 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")

get_active_event

get_active_event(session: Session) -> AimbatEvent

Return the currently active event (i.e. the one being processed).

Parameters:

Name Type Description Default
session Session

SQL session.

required

Returns:

Type Description
AimbatEvent

Active Event

Raises NoResultFound: When no event is active.

Source code in src/aimbat/core/_active_event.py
def get_active_event(session: Session) -> AimbatEvent:
    """
    Return the currently active event (i.e. the one being processed).

    Args:
        session: SQL session.

    Returns:
        Active Event

    Raises
        NoResultFound: When no event is active.
    """

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

    select_active_event = select(AimbatEvent).where(AimbatEvent.active == 1)

    # NOTE: While there technically can be no active event in the database,
    # we typically don't really want to go beyond this point when that is the
    # case. Hence we call `one` rather than `one_or_none`.
    try:
        active_event = session.exec(select_active_event).one()
    except NoResultFound:
        raise NoResultFound(f"No active event found. {HINTS.ACTIVATE_EVENT}")

    logger.debug(f"Active event: {active_event.id}")

    return active_event

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.
    """

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

    return session.exec(select_completed_events).all()

get_data_for_active_event

get_data_for_active_event(
    session: Session,
) -> Sequence[AimbatDataSource]

Returns the data sources belonging to the active event.

Parameters:

Name Type Description Default
session Session

Database session.

required

Returns:

Type Description
Sequence[AimbatDataSource]

Sequence of AimbatDataSource objects belonging to the active event.

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

    Args:
        session: Database session.

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

    logger.info("Getting data sources for active event.")

    statement = (
        select(AimbatDataSource)
        .join(AimbatSeismogram)
        .join(AimbatEvent)
        .where(AimbatEvent.active == 1)
    )
    return session.exec(statement).all()

get_event_parameter

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

Get event parameter value for the active event.

Parameters:

Name Type Description Default
session Session

Database session.

required
name EventParameter

Name of the parameter.

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

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

    active_event = get_active_event(session)

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

    return getattr(active_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}.")

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

    events = session.exec(select_events).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, all_events: bool = False
) -> Sequence[AimbatSeismogram]

Get the selected seismograms for the active avent.

Parameters:

Name Type Description Default
session Session

Database session.

required
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, all_events: bool = False
) -> Sequence[AimbatSeismogram]:
    """Get the selected seismograms for the active avent.

    Args:
        session: Database session.
        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.")
        select_seismograms = (
            select(AimbatSeismogram)
            .join(AimbatSeismogramParameters)
            .where(AimbatSeismogramParameters.select == 1)
        )
    else:
        logger.debug("Selecting seismograms for active event only.")
        select_seismograms = (
            select(AimbatSeismogram)
            .join(AimbatSeismogramParameters)
            .join(AimbatEvent)
            .where(AimbatSeismogramParameters.select == 1)
            .where(AimbatEvent.active == 1)
        )

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

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

    return seismograms

get_snapshots

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

Get the snapshots for the active avent.

Parameters:

Name Type Description Default
session Session

Database session.

required
all_events bool

Get the selected snapshots for all events.

False

Returns: Snapshots.

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

    Args:
        session: Database session.
        all_events: Get the selected snapshots for all events.

    Returns: Snapshots.
    """

    logger.info("Getting AIMBAT snapshots.")

    statement = (
        select(AimbatSnapshot)
        .join(AimbatEvent)
        .where(AimbatEvent.active == True if not all_events else true())  # noqa: E712
    )

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

get_stations_in_active_event

get_stations_in_active_event(
    session: Session, as_json: bool
) -> Sequence[AimbatStation] | list[dict[str, Any]]

Get the stations for the active event.

Parameters:

Name Type Description Default
session Session

Database session.

required

Returns: Stations in active event.

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

    Args:
        session: Database session.

    Returns: Stations in active event.
    """
    logger.info("Getting stations for active event.")

    statement = (
        select(AimbatStation)
        .distinct()
        .join(AimbatSeismogram)
        .join(AimbatEvent)
        .where(AimbatEvent.active == True)  # noqa: E712
    )

    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_in_event

get_stations_in_event(
    session: Session, event: AimbatEvent
) -> Sequence[AimbatStation]

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

Returns: Stations in event.

Source code in src/aimbat/core/_station.py
def get_stations_in_event(
    session: Session, event: AimbatEvent
) -> Sequence[AimbatStation]:
    """Get the stations for a particular event.

    Args:
        session: Database session.
        event: Event to return stations for.

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

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

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

    return stations

get_stations_with_event_seismogram_count

get_stations_with_event_seismogram_count(
    session: Session, as_json: bool
) -> (
    Sequence[tuple[AimbatStation, int, int]]
    | list[dict[str, Any]]
)

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

Parameters:

Name Type Description Default
session Session

Database session.

required
as_json bool

Whether to return the result as JSON.

required

A sequence of tuples containing the station, count of seismograms

Type Description
Sequence[tuple[AimbatStation, int, int]] | list[dict[str, Any]]

and count of events, or a JSON string if as_json is True.

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

    Args:
        session: Database session.
        as_json: Whether to return the result as JSON.

    Returns: A sequence of tuples containing the station, count of seismograms
        and count of events, or a JSON string if as_json is True.
    """
    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}")
    results = session.exec(statement).all()

    if not as_json:
        return results

    formatted_results = []

    for row in results:
        # 1. Dump the station to a dict. mode="json" safely converts UUIDs/Datetimes to strings!
        station_dict = row[0].model_dump(mode="json")

        # 2. Add the counts directly to the dictionary
        station_dict["seismogram_count"] = row[1]
        station_dict["event_count"] = row[2]

        # 3. Add to our final list
        formatted_results.append(station_dict)

    return formatted_results

plot_all_seismograms

plot_all_seismograms(
    session: Session, use_qt: bool = False
) -> Figure

Plot all seismograms for a particular event ordered by great circle distance.

Parameters:

Name Type Description Default
use_qt bool

Plot with pqtgraph instead of pyplot

False
Source code in src/aimbat/core/_seismogram.py
def plot_all_seismograms(session: Session, use_qt: bool = False) -> Figure:
    """Plot all seismograms for a particular event ordered by great circle distance.

    Args:
        use_qt: Plot with pqtgraph instead of pyplot
    """

    active_event = get_active_event(session)

    if active_event is None:
        raise RuntimeError("No active event set.")

    seismograms = active_event.seismograms

    if len(seismograms) == 0:
        raise RuntimeError("No seismograms found in active event.")

    distance_dict = {
        seismogram.id: distance(seismogram.station, seismogram.event) / 1000
        for seismogram in seismograms
    }
    distance_min = min(distance_dict.values())
    distance_max = max(distance_dict.values())
    scaling_factor = (distance_max - distance_min) / len(seismograms) * 5

    title = seismograms[0].event.time.strftime("Event %Y-%m-%d %H:%M:%S")
    xlabel = "Time of day"
    ylabel = "Epicentral distance [km]"

    plot_widget = None
    if use_qt:
        plot_widget = pg.plot(title=title)
        axis = pg.DateAxisItem()
        plot_widget.setAxisItems({"bottom": axis})
        plot_widget.setLabel("bottom", xlabel)
        plot_widget.setLabel("left", ylabel)
    else:
        fig, ax = plt.subplots()

    for seismogram in seismograms:
        clone = clone_to_mini(MiniSeismogram, seismogram)
        detrend(clone)
        normalize(clone)
        plot_data = clone.data * scaling_factor + distance_dict[seismogram.id]
        if use_qt and plot_widget is not None:
            times = unix_time_array(clone)
            plot_widget.plot(times, plot_data)
        else:
            times = time_array(clone)
            ax.plot(
                times,
                plot_data,
                scalex=True,
                scaley=True,
            )
    if not use_qt:
        plt.xlabel(xlabel=xlabel)
        plt.ylabel(ylabel=ylabel)
        plt.gcf().autofmt_xdate()
        fmt = mdates.DateFormatter("%H:%M:%S")
        plt.gca().xaxis.set_major_formatter(fmt)
        plt.title(title)
        plt.show()
    return fig

plot_iccs_seismograms

plot_iccs_seismograms(
    iccs: ICCS, context: bool, all: bool
) -> None

Plot the ICCS seismograms as an image.

Parameters:

Name Type Description Default
iccs ICCS

ICCS instance.

required
context bool

Whether to use seismograms with extra context.

required
all bool

Whether to plot all seismograms.

required
Source code in src/aimbat/core/_iccs.py
def plot_iccs_seismograms(iccs: ICCS, context: bool, all: bool) -> None:
    """Plot the ICCS seismograms as an image.

    Args:
        iccs: ICCS instance.
        context: Whether to use seismograms with extra context.
        all: Whether to plot all seismograms.
    """

    logger.info("Plotting ICCS seismograms for active event.")

    _plot_seismograms(iccs, context, all)

plot_stack

plot_stack(iccs: ICCS, context: bool, all: bool) -> None

Plot the ICCS stack.

Parameters:

Name Type Description Default
iccs ICCS

ICCS instance.

required
context bool

Whether to use seismograms with extra context.

required
all bool

Whether to plot all seismograms.

required
Source code in src/aimbat/core/_iccs.py
def plot_stack(iccs: ICCS, context: bool, all: bool) -> None:
    """Plot the ICCS stack.

    Args:
        iccs: ICCS instance.
        context: Whether to use seismograms with extra context.
        all: Whether to plot all seismograms.
    """

    logger.info("Plotting ICCS stack for active event.")
    _plot_stack(iccs, context, all)

print_data_table

print_data_table(
    session: Session, short: bool, all_events: bool = False
) -> None

Print a pretty table with information about the data sources in the database.

Parameters:

Name Type Description Default
short bool

Shorten UUIDs and format data.

required
all_events bool

Print all files instead of limiting to the active event.

False
Source code in src/aimbat/core/_data.py
def print_data_table(session: Session, short: bool, all_events: bool = False) -> None:
    """Print a pretty table with information about the data sources in the database.

    Args:
        short: Shorten UUIDs and format data.
        all_events: Print all files instead of limiting to the active event.
    """

    logger.info("Printing data sources table.")

    if all_events:
        aimbat_data_sources = session.exec(select(AimbatDataSource)).all()
        title = "Data sources for all events"
    else:
        active_event = get_active_event(session)
        aimbat_data_sources = get_data_for_active_event(session)
        time = (
            active_event.time.strftime("%Y-%m-%d %H:%M:%S")
            if short
            else active_event.time
        )
        id = uuid_shortener(session, active_event) if short else active_event.id
        title = f"Data sources for event {time} (ID={id})"

    logger.debug(f"Found {len(aimbat_data_sources)} data sources in total.")

    rows = [
        [
            uuid_shortener(session, a) if short else str(a.id),
            str(a.datatype),
            str(a.sourcename),
            (uuid_shortener(session, a.seismogram) if short else str(a.seismogram.id)),
        ]
        for a in aimbat_data_sources
    ]

    table = make_table(title=title)

    table.add_column(
        "ID (shortened)" if short else "ID",
        justify="center",
        style=TABLE_STYLING.id,
        no_wrap=True,
    )
    table.add_column("Datatype", justify="center", style=TABLE_STYLING.mine)
    table.add_column("Source", justify="left", style=TABLE_STYLING.mine, no_wrap=True)
    table.add_column(
        "Seismogram ID", justify="center", style=TABLE_STYLING.linked, no_wrap=True
    )

    for row in rows:
        table.add_row(*row)

    console = Console()
    console.print(table)

print_event_parameter_table

print_event_parameter_table(
    session: Session, short: bool, all_events: bool
) -> None

Print a pretty table with AIMBAT parameter values for the active event.

Parameters:

Name Type Description Default
short bool

Shorten and format the output to be more human-readable.

required
all_events bool

Whether to print parameters for all events or just the active one.

required
Source code in src/aimbat/core/_event.py
def print_event_parameter_table(
    session: Session, short: bool, all_events: bool
) -> None:
    """Print a pretty table with AIMBAT parameter values for the active event.

    Args:
        short: Shorten and format the output to be more human-readable.
        all_events: Whether to print parameters for all events or just the active one.
    """

    if all_events:
        logger.info("Printing AIMBAT event parameters table for all events.")
        json_to_table(
            data=dump_event_parameter_table_to_json(
                session, all_events=True, as_string=False
            ),
            title="Event parameters for all events",
            skip_keys=["id"],
            column_order=[
                "event_id",
                "completed",
                "window_pre",
                "window_post",
                "min_ccnorm",
            ],
            formatters={
                "event_id": lambda x: (
                    uuid_shortener(session, AimbatEvent, str_uuid=x) if short else x
                ),
            },
            common_column_kwargs={"highlight": True},
            column_kwargs={
                "event_id": {
                    "header": "Event ID (shortened)" if short else "Event ID",
                    "justify": "center",
                    "style": TABLE_STYLING.mine,
                },
            },
        )
    else:
        logger.info("Printing AIMBAT event parameters table for active event.")

        active_event = get_active_event(session)
        json_to_table(
            data=active_event.parameters.model_dump(mode="json"),
            title=f"Event parameters for event: {uuid_shortener(session, active_event) if short else str(active_event.id)}",
            skip_keys=["id", "event_id"],
            common_column_kwargs={"highlight": True},
            column_kwargs={
                "Key": {
                    "header": "Parameter",
                    "justify": "left",
                    "style": TABLE_STYLING.id,
                },
            },
        )

print_event_table

print_event_table(session: Session, short: bool) -> None

Print a pretty table with AIMBAT events.

Parameters:

Name Type Description Default
session Session

Database session.

required
short bool

Shorten and format the output to be more human-readable.

required
Source code in src/aimbat/core/_event.py
def print_event_table(session: Session, short: bool) -> None:
    """Print a pretty table with AIMBAT events.

    Args:
        session: Database session.
        short: Shorten and format the output to be more human-readable.
    """

    logger.info("Printing AIMBAT events table.")

    json_to_table(
        data=dump_event_table_to_json(session, as_string=False),
        title="AIMBAT Events",
        column_order=[
            "id",
            "active",
            "time",
            "latitude",
            "longitude",
            "depth",
            "completed",
            "seismogram_count",
            "station_count",
        ],
        formatters={
            "id": lambda x: (
                uuid_shortener(session, AimbatEvent, str_uuid=x) if short else x
            ),
            "active": TABLE_STYLING.bool_formatter,
            "time": lambda x: TABLE_STYLING.timestamp_formatter(Timestamp(x), short),
            "latitude": lambda x: f"{x:.3f}" if short else str(x),
            "longitude": lambda x: f"{x:.3f}" if short else str(x),
            "depth": lambda x: f"{x:.0f}" if short and x is not None else str(x),
            "completed": TABLE_STYLING.bool_formatter,
        },
        common_column_kwargs={"justify": "center"},
        column_kwargs={
            "id": {
                "header": "ID (shortened)" if short else "ID",
                "style": TABLE_STYLING.id,
                "no_wrap": True,
            },
            "active": {"style": TABLE_STYLING.mine, "no_wrap": True},
            "time": {
                "header": "Date & Time",
                "style": TABLE_STYLING.mine,
                "no_wrap": True,
            },
            "latitude": {"style": TABLE_STYLING.mine},
            "longitude": {"style": TABLE_STYLING.mine},
            "depth": {"style": TABLE_STYLING.mine},
            "completed": {"style": TABLE_STYLING.parameters},
            "seismogram_count": {
                "header": "# Seismograms",
                "style": TABLE_STYLING.linked,
            },
            "station_count": {
                "header": "# Stations",
                "style": TABLE_STYLING.linked,
            },
        },
    )

print_project_info

print_project_info(engine: Engine) -> None

Show AIMBAT project information.

Raises:

Type Description
RuntimeError

If no project found.

Source code in src/aimbat/core/_project.py
def print_project_info(engine: Engine) -> None:
    """Show AIMBAT project information.

    Raises:
        RuntimeError: If no project found.
    """

    logger.info("Printing project info.")

    if not _project_exists(engine):
        raise RuntimeError(
            'No AIMBAT project found. Try running "aimbat project create" first.'
        )

    with Session(engine) as session:
        grid = Table.grid(expand=False)
        grid.add_column()
        grid.add_column(justify="left")
        if engine.driver == "pysqlite":
            if engine.url.database == ":memory:":
                grid.add_row("AIMBAT Project: ", "in-memory database")
            else:
                grid.add_row("AIMBAT Project File: ", str(engine.url.database))

        events = len(session.exec(select(AimbatEvent)).all())
        completed_events = len(event.get_completed_events(session))
        stations = len(session.exec(select(AimbatStation)).all())
        seismograms = len(session.exec(select(AimbatSeismogram)).all())
        selected_seismograms = len(
            seismogram.get_selected_seismograms(session, all_events=True)
        )

        grid.add_row(
            "Number of Events (total/completed): ",
            f"({events}/{completed_events})",
        )

        try:
            active_event = get_active_event(session)
            active_event_id = active_event.id
            active_stations = len(station.get_stations_in_event(session, active_event))
            seismograms_in_event = len(active_event.seismograms)
            selected_seismograms_in_event = len(
                seismogram.get_selected_seismograms(session)
            )
        except NoResultFound:
            active_event_id = None
            active_stations = None
            seismograms_in_event = None
            selected_seismograms_in_event = None
        grid.add_row("Active Event ID: ", f"{active_event_id}")
        grid.add_row(
            "Number of Stations in Project (total/active event): ",
            f"({stations}/{active_stations})",
        )

        grid.add_row(
            "Number of Seismograms in Project (total/selected): ",
            f"({seismograms}/{selected_seismograms})",
        )
        grid.add_row(
            "Number of Seismograms in Active Event (total/selected): ",
            f"({seismograms_in_event}/{selected_seismograms_in_event})",
        )

        console = Console()
        console.print(
            Panel(grid, title="Project Info", title_align="left", border_style="dim")
        )

print_seismogram_parameter_table

print_seismogram_parameter_table(
    session: Session, short: bool
) -> None

Print a pretty table with AIMBAT seismogram parameter values for the active event.

Parameters:

Name Type Description Default
short bool

Shorten and format the output to be more human-readable.

required
Source code in src/aimbat/core/_seismogram.py
def print_seismogram_parameter_table(session: Session, short: bool) -> None:
    """Print a pretty table with AIMBAT seismogram parameter values for the active event.

    Args:
        short: Shorten and format the output to be more human-readable.
    """

    logger.info("Printing AIMBAT seismogram parameters table for active event.")

    active_event = get_active_event(session)
    title = f"Seismogram parameters for event: {uuid_shortener(session, active_event) if short else str(active_event.id)}"

    json_to_table(
        data=dump_seismogram_parameter_table_to_json(
            session, all_events=False, as_string=False
        ),
        title=title,
        skip_keys=["id"],
        column_order=["seismogram_id", "select"],
        common_column_kwargs={"highlight": True},
        formatters={
            "seismogram_id": lambda x: (
                uuid_shortener(session, AimbatSeismogram, str_uuid=x) if short else x
            ),
        },
        column_kwargs={
            "seismogram_id": {
                "header": "Seismogram ID (shortened)" if short else "Seismogram ID",
                "justify": "center",
                "style": TABLE_STYLING.mine,
            },
        },
    )

print_seismogram_table

print_seismogram_table(
    session: Session, short: bool, all_events: bool = False
) -> None

Prints a pretty table with AIMBAT seismograms.

Parameters:

Name Type Description Default
short bool

Shorten and format the output to be more human-readable.

required
all_events bool

Print seismograms for all events.

False
Source code in src/aimbat/core/_seismogram.py
def print_seismogram_table(
    session: Session, short: bool, all_events: bool = False
) -> None:
    """Prints a pretty table with AIMBAT seismograms.

    Args:
        short: Shorten and format the output to be more human-readable.
        all_events: Print seismograms for all events.
    """

    logger.info("Printing AIMBAT seismogram table.")

    title = "AIMBAT seismograms for all events"
    seismograms = None

    if all_events:
        logger.debug("Selecting seismograms for all events.")
        seismograms = session.exec(select(AimbatSeismogram)).all()
    else:
        logger.debug("Selecting seismograms for active event only.")
        active_event = get_active_event(session)
        seismograms = active_event.seismograms
        if short:
            title = f"AIMBAT seismograms for event {active_event.time.strftime('%Y-%m-%d %H:%M:%S')} (ID={event.uuid_shortener(session, active_event)})"
        else:
            title = f"AIMBAT seismograms for event {active_event.time} (ID={active_event.id})"

    logger.debug(f"Found {len(seismograms)} seismograms for the table.")

    table = make_table(title=title)
    table.add_column(
        "ID (shortened)" if short else "ID",
        justify="center",
        style=TABLE_STYLING.id,
        no_wrap=True,
    )
    table.add_column(
        "Selected", justify="center", style=TABLE_STYLING.mine, no_wrap=True
    )
    table.add_column("NPTS", justify="center", style=TABLE_STYLING.mine, no_wrap=True)
    table.add_column("Delta", justify="center", style=TABLE_STYLING.mine, no_wrap=True)
    table.add_column(
        "Data ID", justify="center", style=TABLE_STYLING.linked, no_wrap=True
    )
    table.add_column("Station ID", justify="center", style=TABLE_STYLING.linked)
    table.add_column("Station Name", justify="center", style=TABLE_STYLING.linked)
    if all_events:
        table.add_column("Event ID", justify="center", style=TABLE_STYLING.linked)

    for seismogram in seismograms:
        logger.debug(f"Adding seismogram with ID {seismogram.id} to the table.")
        row = [
            (uuid_shortener(session, seismogram) if short else str(seismogram.id)),
            TABLE_STYLING.bool_formatter(seismogram.parameters.select),
            str(len(seismogram.data)),
            str(seismogram.delta.total_seconds()),
            (
                uuid_shortener(session, seismogram.datasource)
                if short
                else str(seismogram.datasource.id)
            ),
            (
                uuid_shortener(session, seismogram.station)
                if short
                else str(seismogram.station.id)
            ),
            f"{seismogram.station.name} - {seismogram.station.network}",
        ]

        if all_events:
            row.append(
                uuid_shortener(session, seismogram.event)
                if short
                else str(seismogram.event.id)
            )
        table.add_row(*row)

    console = Console()
    console.print(table)

print_snapshot_table

print_snapshot_table(
    session: Session, short: bool, all_events: bool
) -> None

Print a pretty table with AIMBAT snapshots.

Uses the snapshots portion of :func:dump_snapshot_tables_to_json and renders it via :func:~aimbat.utils.json_to_table.

Parameters:

Name Type Description Default
session Session

Database session.

required
short bool

Shorten and format the output to be more human-readable.

required
all_events bool

Print all snapshots instead of limiting to the active event.

required
Source code in src/aimbat/core/_snapshot.py
def print_snapshot_table(session: Session, short: bool, all_events: bool) -> None:
    """Print a pretty table with AIMBAT snapshots.

    Uses the ``snapshots`` portion of :func:`dump_snapshot_tables_to_json`
    and renders it via :func:`~aimbat.utils.json_to_table`.

    Args:
        session: Database session.
        short: Shorten and format the output to be more human-readable.
        all_events: Print all snapshots instead of limiting to the active event.
    """

    logger.info("Printing AIMBAT snapshots table.")

    title = "AIMBAT snapshots for all events"

    if not all_events:
        active_event = get_active_event(session)
        if short:
            title = f"AIMBAT snapshots for event {active_event.time.strftime('%Y-%m-%d %H:%M:%S')} (ID={uuid_shortener(session, active_event)})"
        else:
            title = (
                f"AIMBAT snapshots for event {active_event.time} (ID={active_event.id})"
            )

    data = dump_snapshot_tables_to_json(session, all_events, as_string=False)
    snapshot_data = data["snapshots"]

    column_order = ["id", "date", "comment", "seismogram_count"]
    if all_events:
        column_order.append("event_id")

    skip_keys = [] if all_events else ["event_id"]

    json_to_table(
        data=snapshot_data,
        title=title,
        column_order=column_order,
        skip_keys=skip_keys,
        formatters={
            "id": lambda x: (
                uuid_shortener(session, AimbatSnapshot, str_uuid=x) if short else x
            ),
            "date": lambda x: TABLE_STYLING.timestamp_formatter(Timestamp(x), short),
            "event_id": lambda x: (
                uuid_shortener(session, AimbatEvent, str_uuid=x) if short else x
            ),
        },
        common_column_kwargs={"justify": "center"},
        column_kwargs={
            "id": {
                "header": "ID (shortened)" if short else "ID",
                "style": TABLE_STYLING.id,
                "no_wrap": True,
            },
            "date": {
                "header": "Date & Time",
                "style": TABLE_STYLING.mine,
                "no_wrap": True,
            },
            "comment": {"style": TABLE_STYLING.mine},
            "seismogram_count": {
                "header": "# Seismograms",
                "style": TABLE_STYLING.linked,
            },
            "event_id": {
                "header": "Event ID (shortened)" if short else "Event ID",
                "style": TABLE_STYLING.linked,
            },
        },
    )

print_station_table

print_station_table(
    session: Session, short: bool, all_events: bool = False
) -> None

Prints a pretty table with AIMBAT stations.

Parameters:

Name Type Description Default
session Session

Database session.

required
short bool

Shorten and format the output to be more human-readable.

required
all_events bool

Print stations for all events.

False
Source code in src/aimbat/core/_station.py
def print_station_table(
    session: Session, short: bool, all_events: bool = False
) -> None:
    """Prints a pretty table with AIMBAT stations.

    Args:
        session: Database session.
        short: Shorten and format the output to be more human-readable.
        all_events: Print stations for all events.
    """
    logger.info("Printing station table.")

    title = "AIMBAT stations for all events"

    if all_events:
        logger.debug("Selecting all AIMBAT stations.")
        data = get_stations_with_event_seismogram_count(session, as_json=True)
    else:
        logger.debug("Selecting AIMBAT stations used by active event.")
        active_event = get_active_event(session)
        data = get_stations_in_active_event(session, as_json=True)

        if short:
            title = f"AIMBAT stations for event {active_event.time.strftime('%Y-%m-%d %H:%M:%S')} (ID={uuid_shortener(session, active_event)})"
        else:
            title = (
                f"AIMBAT stations for event {active_event.time} (ID={active_event.id})"
            )

    column_order = [
        "id",
        "name",
        "network",
        "channel",
        "location",
        "latitude",
        "longitude",
        "elevation",
    ]
    if all_events:
        column_order.extend(["seismogram_count", "event_count"])

    column_kwargs: dict[str, dict[str, Any]] = {
        "id": {
            "header": "ID (shortened)" if short else "ID",
            "style": TABLE_STYLING.id,
            "justify": "center",
            "no_wrap": True,
        },
        "name": {
            "header": "Name",
            "style": TABLE_STYLING.mine,
            "justify": "center",
            "no_wrap": True,
        },
        "network": {
            "header": "Network",
            "style": TABLE_STYLING.mine,
            "justify": "center",
            "no_wrap": True,
        },
        "channel": {
            "header": "Channel",
            "style": TABLE_STYLING.mine,
            "justify": "center",
        },
        "location": {
            "header": "Location",
            "style": TABLE_STYLING.mine,
            "justify": "center",
        },
        "latitude": {
            "header": "Latitude",
            "style": TABLE_STYLING.mine,
            "justify": "center",
        },
        "longitude": {
            "header": "Longitude",
            "style": TABLE_STYLING.mine,
            "justify": "center",
        },
        "elevation": {
            "header": "Elevation",
            "style": TABLE_STYLING.mine,
            "justify": "center",
        },
        "seismogram_count": {
            "header": "# Seismograms",
            "style": TABLE_STYLING.linked,
            "justify": "center",
        },
        "event_count": {
            "header": "# Events",
            "style": TABLE_STYLING.linked,
            "justify": "center",
        },
    }

    formatters = {
        "id": lambda x: (
            uuid_shortener(session, AimbatStation, str_uuid=x) if short else str(x)
        ),
        "latitude": lambda x: f"{x:.3f}" if short else str(x),
        "longitude": lambda x: f"{x:.3f}" if short else str(x),
        "elevation": lambda x: f"{x:.0f}" if short else str(x),
    }

    json_to_table(
        data,
        title=title,
        column_order=column_order,
        column_kwargs=column_kwargs,
        formatters=formatters,
    )

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, v in rollback_event_parameters.model_dump().items():
        setattr(current_event_parameters, k, v)

    session.add(current_event_parameters)

    for seismogram_parameters_snapshot in snapshot.seismogram_parameters_snapshots:
        # create object with just the parameters
        rollback_seismogram_parameters = AimbatSeismogramParametersBase.model_validate(
            seismogram_parameters_snapshot
        )
        logger.debug(
            f"Using seismogram parameters snapshot with id={seismogram_parameters_snapshot.id} for rollback."
        )
        # setting attributes explicitly brings them into the session
        current_seismogram_parameters = seismogram_parameters_snapshot.parameters
        for parameter, value in rollback_seismogram_parameters.model_dump().items():
            setattr(current_seismogram_parameters, parameter, value)
        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 ICCS algorithm.

Parameters:

Name Type Description Default
session Session

Database session.

required
iccs ICCS

ICCS instance.

required
autoflip bool

Whether to automatically flip seismograms.

required
autoselect bool

Whether to automatically select seismograms.

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

    Args:
        session: Database session.
        iccs: ICCS instance.
        autoflip: Whether to automatically flip seismograms.
        autoselect: Whether to automatically select seismograms.
    """

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

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

run_mccc

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

Run MCCC algorithm.

Parameters:

Name Type Description Default
session Session

SQLModel session.

required
iccs ICCS

ICCS instance.

required
all_seismograms bool

Whether to include all seismograms in the MCCC processing, or just the selected ones.

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

    Args:
        session: SQLModel session.
        iccs: ICCS instance.
        all_seismograms: Whether to include all seismograms in the MCCC processing, or just the selected ones.
    """

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

    active_event = get_active_event(session)
    min_cc = active_event.parameters.mccc_min_ccnorm
    damping = active_event.parameters.mccc_damp

    cc_seismograms = (
        iccs.cc_seismograms
        if all_seismograms
        else [s for s in iccs.cc_seismograms if s.parent_seismogram.select]
    )

    delay_times, delay_stdev, rmse = mccc(cc_seismograms, min_cc, damping)

    for cc_seismogram, delay_time in zip(cc_seismograms, delay_times):
        logger.debug(
            f"Applying MCCC delay time delta {delay_time.total_seconds():.2f} s to seismogram {cast(AimbatSeismogram, cc_seismogram.parent_seismogram).id}."
        )

        t1 = (
            cc_seismogram.parent_seismogram.t1
            or cc_seismogram.parent_seismogram.t0 - delay_time
        )
        cc_seismogram.parent_seismogram.t1 = t1
    session.commit()

set_active_event

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

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

Parameters:

Name Type Description Default
session Session

SQL session.

required
event AimbatEvent

AIMBAT Event to set as active.

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

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

    logger.info(f"Activating {event=}")

    with suppress(NoResultFound):
        if event.id == get_active_event(session).id:
            return

    clear_seismogram_cache()
    event.active = True
    session.add(event)
    session.commit()

set_active_event_by_id

set_active_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 active one.

required

Raises:

Type Description
ValueError

If no event with the given ID is found.

Source code in src/aimbat/core/_active_event.py
def set_active_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 active one.

    Raises:
        ValueError: If no event with the given ID is found.
    """
    logger.info(f"Setting active 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}. {HINTS.LIST_EVENTS}"
        )

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

set_event_parameter

set_event_parameter(
    session: Session,
    name: EventParameter,
    value: Timedelta | bool | float | str,
) -> None

Set event parameter value for the active event.

Parameters:

Name Type Description Default
session Session

Database session.

required
name EventParameter

Name of the parameter.

required
value Timedelta | bool | float | str

Value to set.

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

    Args:
        session: Database session.
        name: Name of the parameter.
        value: Value to set.
    """

    active_event = get_active_event(session)

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

    parameters = AimbatEventParametersBase.model_validate(
        active_event.parameters, update={name: value}
    )
    setattr(active_event.parameters, name, getattr(parameters, name))
    session.add(active_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)

update_min_ccnorm

update_min_ccnorm(
    session: Session, iccs: ICCS, context: bool, all: bool
) -> None

Update the minimum cross correlation coefficient for the active event.

Parameters:

Name Type Description Default
iccs ICCS

ICCS instance.

required
context bool

Whether to use seismograms with extra context.

required
all bool

Whether to plot all seismograms.

required
Source code in src/aimbat/core/_iccs.py
def update_min_ccnorm(session: Session, iccs: ICCS, context: bool, all: bool) -> None:
    """Update the minimum cross correlation coefficient for the active event.

    Args:
        iccs: ICCS instance.
        context: Whether to use seismograms with extra context.
        all: Whether to plot all seismograms.
    """

    logger.info("Updating minimum cross correlation coefficient for active event.")

    logger.debug(f"Current {iccs.min_ccnorm = }.")
    _update_min_ccnorm(iccs, context, all)
    logger.debug(f"Updated {iccs.min_ccnorm = }.")

    active_event = get_active_event(session)
    active_event.parameters.min_ccnorm = float(iccs.min_ccnorm)
    session.commit()

update_pick

update_pick(
    session: Session,
    iccs: ICCS,
    context: bool,
    all: bool,
    use_seismogram_image: bool,
) -> None

Update the pick for the active event.

Parameters:

Name Type Description Default
iccs ICCS

ICCS instance.

required
context bool

Whether to use seismograms with extra context.

required
all bool

Whether to plot all seismograms.

required
use_seismogram_image bool

Whether to use the seismogram image to update pick.

required
Source code in src/aimbat/core/_iccs.py
def update_pick(
    session: Session, iccs: ICCS, context: bool, all: bool, use_seismogram_image: bool
) -> None:
    """Update the pick for the active event.

    Args:
        iccs: ICCS instance.
        context: Whether to use seismograms with extra context.
        all: Whether to plot all seismograms.
        use_seismogram_image: Whether to use the seismogram image to update pick.
    """

    logger.info("Updating pick for active event.")

    _update_pick(iccs, context, all, use_seismogram_image)
    session.commit()

update_timewindow

update_timewindow(
    session: Session,
    iccs: ICCS,
    context: bool,
    all: bool,
    use_seismogram_image: bool,
) -> None

Update the time window for the active event.

Parameters:

Name Type Description Default
iccs ICCS

ICCS instance.

required
context bool

Whether to use seismograms with extra context.

required
all bool

Whether to plot all seismograms.

required
use_seismogram_image bool

Whether to use the seismogram image to update pick.

required
Source code in src/aimbat/core/_iccs.py
def update_timewindow(
    session: Session, iccs: ICCS, context: bool, all: bool, use_seismogram_image: bool
) -> None:
    """Update the time window for the active event.

    Args:
        iccs: ICCS instance.
        context: Whether to use seismograms with extra context.
        all: Whether to plot all seismograms.
        use_seismogram_image: Whether to use the seismogram image to update pick.
    """

    logger.info("Updating time window for active event.")

    logger.debug(f"Current {iccs.window_pre = }, {iccs.window_post = }.")
    _update_timewindow(iccs, context, all, use_seismogram_image)
    logger.debug(f"Updated {iccs.window_pre = }, {iccs.window_post = }.")

    active_event = get_active_event(session)
    active_event.parameters.window_pre = iccs.window_pre
    active_event.parameters.window_post = iccs.window_post
    session.commit()