TGSAI/mdio-python

Add seismic geometry abstractions

Opened this issue · 0 comments

It would be nice to have geometry abstractions for standard interface and custom / geometry specific exception handling.

This has the following pros:

  1. Common interface for coordinate conversions.
  2. Trace iterators based on the type of data.
  3. Enforce usage of methods for geometry instances that may be added later.
  4. Improve maintainability.
  5. Allow custom things to be added, i.e., for shots, we add the conversion from unwrapped channels to wrapped channels unwrap_channels, and we still have a base implementation that should follow the extensible interface.
  6. Encapsulate the logic for geometry specific chunk size and access pattern configurations

Long shot, but cython or numba jit versions may be even better. xarray can also be used to handle named dimensions etc.

Would inherit from a base class like

# mdio/segy/geometry.py

from abc import ABC


class SeismicGeometry(ABC):
    def __init__(self, args, kwargs):
        ...

    @abstractmethod
    def __iter__(self):
        ...

    @abstractmethod
    def __getitem__(self):
        ...

    @abstractmethod
    def xy_to_grid(self, x, y, method="nearest"):
        ...

    @property
    @abstractmethod
    def num_traces(self):
       ...

Then we would have 3D as something like

from mdio.segy.geometry import SeismicGeometry


class SeismicStack3d(SeismicGeometry):
    def __init__(self, inlines, crosslines, samples):
        # set attributes, initialize grid etc.

    def __iter__(self):
        # logic to iterate traces on spatial il/xl grid

    @abstractmethod
    def xy_to_grid(self, x, y, method="nearest"):
        # logic to convert CDP-X CDP-Y to inline and crossline

    @property
    def num_traces(self):
        return self.get_size("inline") * self.get_size("crossline")

Or 3D shots like

from mdio.segy.geometry import SeismicGeometry


class SeismicShot3d(SeismicGeometry):
    def __init__(self, shots, cables, channels, samples):
        # set attributes, initialize grid etc.

    def __iter__(self):
        # logic to iterate traces on shot grid

    @abstractmethod
    def xy_to_grid(self, x, y, method="nearest"):
        # logic to convert SHOT-X SHOT-Y to shot number

    @property
    def num_traces(self):
        return self.get_size("shot") * self.get_size("cable") * self.get_size("channel")

    @def unwrap_channels(self, channels_per_streamer: int):
        return self.channel % channels_per_streamer + 1

and so on.