# obspy.io.sac.sactrace

Python interface to the Seismic Analysis Code (SAC) file format.

copyright: | The Los Alamos National Security, LLC, Yannik Behr, C. J. Ammon, C. Satriano, L. Krischer, and J. MacCarthy
license: | GNU Lesser General Public License, Version 3 (https://www.gnu.org/copyleft/lesser.html)

The SACTrace object maintains consistency between SAC headers and manages header values in a user-friendly way. This includes some value-checking, native Python logicals (True, False) and nulls (None) instead of SAC’s 0, 1, or -12345...

SAC headers are implemented as properties, with appropriate getters and setters.

## Features

1. Read and write SAC binary or ASCII
   - autodetect or specify expected byteorder
   - optional file size checking and/or header consistency checks
   - header-only reading and writing
   - “overwrite OK” checking (‘lovrok’ header)
2. Convenient access and manipulation of relative and absolute time headers
3. User-friendly header printing/viewing
4. Fast access to header values from attributes
   - With type checking, null handling, and enumerated value checking
5. Convert to/from ObsPy Traces
   - Conversion from ObsPy Trace to SAC trace retains detected previous SAC header values.
   - Conversion to ObsPy Trace retains the complete SAC header.

## Usage examples

### Read/write SAC files

    # read from a binary file
    sac = SACTrace.read(filename)

    # read header only
    sac = SACTrace.read(filename, headonly=True)

    # write header-only, file must exist
    sac.write(filename, headonly=True)

    # read from an ASCII file
    sac = SACTrace.read(filename, ascii=True)

    # write a binary SAC file for a Sun machine
    sac.write(filename, byteorder='big')

### Build a SACTrace from a header dictionary and data array

Example

    >>> header = {'kstnm': 'ANMO', 'kcmpnm': 'BHZ', 'stla': 40.5, 'stlo': -108.23,
    ...           'evla': -15.123, 'evlo': 123, 'evdp': 50, 'nzyear': 2012,
    ...           'nzjday': 123, 'nzhour': 13, 'nzmin': 43, 'nzsec': 17,
    ...           'nzmsec': 100, 'delta': 1.0/40}
    >>> sac = SACTrace(data=np.random.random(100), **header)
    >>> print(sac)
    Reference Time = 05/02/2012 (123) 13:43:17.100000
       iztype IB: begin time
    b          = 0.0
    delta      = 0.0250000...
    e          = 2.4750000...
    evdp       = 50.0
    evla       = -15.123000...
    evlo       = 123.0
    iftype     = itime
    internal0  = 2.0
    iztype     = ib
    kcmpnm     = BHZ
    kstnm      = ANMO
    lcalda     = False
    leven      = True
    lovrok     = True
    lpspol     = True
    npts       = 100
    nvhdr      = 6
    nzhour     = 13
    nzjday     = 123
    nzmin      = 43
    nzmsec     = 100
    nzsec      = 17
    nzyear     = 2012
    stla       = 40.5
    stlo       = -108.23000...

### Reference-time and relative time headers

Example

    >>> sac = SACTrace(nzyear=2000, nzjday=1, nzhour=0, nzmin=0, nzsec=0,
    ...                nzmsec=0, t1=23.5, data=np.arange(100))
    >>> print(sac.reftime)
    2000-01-01T00:00:00.000000Z
    >>> sac.b, sac.e, sac.t1
    (0.0, 99.0, 23.5)

Move reference time by relative seconds, relative time headers are preserved.

Example

    >>> sac = SACTrace(nzyear=2000, nzjday=1, nzhour=0, nzmin=0, nzsec=0,
    ...                nzmsec=0, t1=23.5, data=np.arange(100))
    >>> sac.reftime -= 2.5
    >>> sac.b, sac.e, sac.t1
    (2.5, 101.5, 26.0)

Set reference time to new absolute time, relative time headers are preserved.

Example

    >>> sac = SACTrace(nzyear=2000, nzjday=1, nzhour=0, nzmin=0, nzsec=0,
    ...                nzmsec=0, t1=23.5, data=np.arange(100))
    >>> # set the reftime two minutes later
    >>> sac.reftime = UTCDateTime(2000, 1, 1, 0, 2, 0, 0)
    >>> sac.b, sac.e, sac.t1
    (-120.0, -21.0, -96.5)

### Quick header viewing

Print non-null header values.

Example

    >>> sac = SACTrace()
    >>> print(sac)
    Reference Time = 01/01/1970 (001) 00:00:00.000000
       iztype IB: begin time
    b          = 0.0
    delta      = 1.0
    e          = 0.0
    iftype     = itime
    internal0  = 2.0
    iztype     = ib
    lcalda     = False
    leven      = True
    lovrok     = True
    lpspol     = True
    npts       = 0
    nvhdr      = 6
    nzhour     = 0
    nzjday     = 1
    nzmin      = 0
    nzmsec     = 0
    nzsec      = 0
    nzyear     = 1970

Print relative time header values.

Example

    >>> sac = SACTrace()
    >>> sac.lh('picks')
    Reference Time = 01/01/1970 (001) 00:00:00.000000
       iztype IB: begin time
    a          = None
    b          = 0.0
    e          = 0.0
    f          = None
    o          = None
    t0         = None
    t1         = None
    t2         = None
    t3         = None
    t4         = None
    t5         = None
    t6         = None
    t7         = None
    t8         = None
    t9         = None

### Header values as attributes

Great for interactive use, with (ipython) tab-completion...

    sac.<tab>

    sac.a                 sac.kevnm             sac.nzsec
    sac.az                sac.kf                sac.nzyear
    sac.b                 sac.khole             sac.o
    sac.baz               sac.kinst             sac.odelta
    sac.byteorder         sac.knetwk            sac.read
    sac.cmpaz             sac.ko                sac.reftime
    sac.cmpinc            sac.kstnm             sac.scale
    sac.copy              sac.kt0               sac.stdp
    sac.data              sac.kt1               sac.stel
    sac.delta             sac.kt2               sac.stla
    sac.depmax            sac.kt3               sac.stlo
    sac.depmen            sac.kt4               sac.t0
    sac.depmin            sac.kt5               sac.t1
    sac.dist              sac.kt6               sac.t2
    sac.e                 sac.kt7               sac.t3
    sac.evdp              sac.kt8               sac.t4
    sac.evla              sac.kt9               sac.t5
    sac.evlo              sac.kuser0            sac.t6
    sac.f                 sac.kuser1            sac.t7
    sac.from_obspy_trace  sac.kuser2            sac.t8
    sac.gcarc             sac.lcalda            sac.t9
    sac.idep              sac.leven             sac.to_obspy_trace
    sac.ievreg            sac.lh                sac.unused23
    sac.ievtyp            sac.listhdr           sac.user0
    sac.iftype            sac.lovrok            sac.user1
    sac.iinst             sac.lpspol            sac.user2
    sac.imagsrc           sac.mag               sac.user3
    sac.imagtyp           sac.nevid             sac.user4
    sac.internal0         sac.norid             sac.user5
    sac.iqual             sac.npts              sac.user6
    sac.istreg            sac.nvhdr             sac.user7
    sac.isynth            sac.nwfid             sac.user8
    sac.iztype            sac.nzhour            sac.user9
    sac.ka                sac.nzjday            sac.validate
    sac.kcmpnm            sac.nzmin             sac.write
    sac.kdatrd            sac.nzmsec

...and documentation (in IPython)!

    sac.iztype?

    Type:        property
    String form: <property object at 0x106404940>
    Docstring:
    I    Reference time equivalence:

    * IUNKN (5): Unknown
    * IB (9): Begin time
    * IDAY (10): Midnight of reference GMT day
    * IO (11): Event origin time
    * IA (12): First arrival time
    * ITn (13-22): User defined time pick n, n=0,9

### Convert to/from ObsPy Traces

Example

    >>> from obspy import read
    >>> tr = read()[0]
    >>> print(tr.stats)
             network: BW
             station: RJOB
            location:
             channel: EHZ
           starttime: 2009-08-24T00:20:03.000000Z
             endtime: 2009-08-24T00:20:32.990000Z
       sampling_rate: 100.0
               delta: 0.01
                npts: 3000
               calib: 1.0
        back_azimuth: 100.0
         inclination: 30.0
            response: Channel Response
                ...

    >>> sac = SACTrace.from_obspy_trace(tr)
    >>> print(sac)
    Reference Time = 08/24/2009 (236) 00:20:03.000000
       iztype IB: begin time
    b          = 0.0
    delta      = 0.009999999...
    e          = 29.989999...
    iftype     = itime
    iztype     = ib
    kcmpnm     = EHZ
    knetwk     = BW
    kstnm      = RJOB
    lcalda     = False
    leven      = True
    lovrok     = True
    lpspol     = True
    npts       = 3000
    nvhdr      = 6
    nzhour     = 0
    nzjday     = 236
    nzmin      = 20
    nzmsec     = 0
    nzsec      = 3
    nzyear     = 2009
    scale      = 1.0

    >>> tr2 = sac.to_obspy_trace()
    >>> print(tr2.stats)
             network: BW
             station: RJOB
            location:
             channel: EHZ
           starttime: 2009-08-24T00:20:03.000000Z
             endtime: 2009-08-24T00:20:32.990000Z
       sampling_rate: 100.0
               delta: 0.01
                npts: 3000
               calib: 1.0
                 sac: AttribDict(...)

Private Functions

Warning

Private functions are mainly for internal/developer use and their API might change without notice.

`_get_e` |
`_get_kevnm` |
`_iztype_reftime` | Get the new reftime for a given iztype.
`_set_kevnm` |

Classes

`BoolHeader` |
`DataHeader` |
`EnumHeader` |
`FloatHeader` |
`GeographicHeader` |
`IntHeader` |
`RelativeTimeHeader` |
`SACHeader` |
`SACTrace` | Convenient and consistent in-memory representation of Seismic Analysis Code
`StringHeader` |

### Thank you!

We would like to thank our contributors, whose efforts make this software what it is. These people have helped by writing code and documentation, and by testing. They have created and maintained this product, its associated libraries and applications, our build tools and our web sites.

#### Contributors

- Ackerley, Nick
- Allgeyer, Sebastien
- Ammon, Charles J.
- Antunes, Emanuel
- Arnarsson, Ólafur St.
- Bank, Markus
- Barsch, Robert
- Behr, Yannik
- Bernardi, Fabrizio
- Bernauer, Felix
- Bes de Berc, Maxime
- Beyreuther, Moritz
- Boltz, Shawn
- Bonaimé, Sébastien
- Carothers, Lloyd
- Chamberlain, Calum
- Chambers, Derrick
- Chen, Zhao
- Clark, Adam
- Danecek, Peter
- Egdorf, Sven
- Engels, Fabian
- Ermert, Laura
- Eulenfeld, Tom

- Fabbri, Tommaso
- Falco, Nicholas
- Fee, Jeremy
- Grellier, Clément
- Grunberg, Marc
- Hammer, Conny
- Heimann, Sebastian
- Heiniger, Lukas
- Hope, Gaute
- Igel, Heiner
- Inza, Adolfo
- Isken, Marius
- Ketchum, David
- Koymans, Mathijs
- Kremers, Simon
- Kress, Victor
- Krieger, Lars
- Krischer, Lion
- Kula, Damian
- Käufl, Paul
- Köhler, Andreas
- Lecocq, Thomas
- Leeman, John
- Legovini, Paride

- Lesage, Philippe
- Li, Yulin
- Lomax, Anthony
- Lopes, Rui L.
- MacCarthy, Jonathan
- Maggi, Alessia
- Martin, Henri
- Medlin, Andrew
- Megies, Tobias
- Meschede, Matthias
- Michelini, Alberto
- Miller, Nathaniel C.
- Morgenstern, Bernhard
- Nof, Ran Novitsky
- Panning, Mark P.
- Parker, Tom
- Pestourie, Romain
- Rapagnani, Giovanni
- Reyes, Celso
- Ringler, Adam
- Rothenhäusler, Nicolas
- Russo, Emiliano
- Sales de Andrade, Elliott

- Satriano, Claudio
- Saul, Joachim
- Scheingraber, Chris
- Schneider, Simon
- Sippl, Christian
- Snoke, Arthur
- Stange, Stefan
- Stähler, Simon C.
- Sullivan, Benjamin
- Tian, Dongdong
- Trabant, Chad
- Trani, Luca
- Uieda, Leonardo
- Walker, Andrew
- Walther, Marcus
- Wassermann, Joachim
- Williams, Mark C.
- Winkelman, Andrew
- Zaccarelli, Riccardo
- Zad, Seyed Kasra Hosseini
- Zhu, Lijun
- van Driel, Martin
- van Wijk, Kasper

#### Funds

ObsPy was partially funded by the

- German Science Foundation (DFG) via grant DFG IG 16/9-1
- German Ministry for Education and Research (BMBF), GEOTECHNOLOGIEN grant 03G0646H.
- NERA project (Network of European Research Infrastructures for Earthquake Risk Assessment and Mitigation) under the European Community's Seventh Framework Programme (FP7/2007-2013) grant agreement n° 262330
- Leibniz Institute for Applied Geophysics (LIAG)
- VERCE EU-FP7 project (no. 283543)