{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a9a8212b-3aa1-42ce-990a-57c8bdd31c3f",
   "metadata": {
    "lines_to_next_cell": 0
   },
   "source": [
    "This tutorial deals with reading an SU data set and __creating a SEG-Y file__. Please make sure you have downloaded the test data as outlined in the file \"examples/data/README\" and you ran tutorial #2 to create the required SU file.\n",
    "\n",
    "Let's start by importing some packages (including the seisio package itself) and setting up the logging config."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8543f6b9-4e65-4632-ba04-46f917bf3366",
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "import numpy as np\n",
    "\n",
    "import sys\n",
    "sys.path.insert(1, '../')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "be59f1bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "import seisio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "86fa4cf6",
   "metadata": {},
   "outputs": [],
   "source": [
    "logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s', force=True)\n",
    "log = logging.getLogger(\"main\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56cf9f83-0e3b-4a96-87c2-3f82a11c3662",
   "metadata": {},
   "source": [
    "We read the (previously created) SU file in little-endian byte order and create a SEG-Y file, but as opposed to the original 'Line_001.sgy' file we use the IEEE floating-point data format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "21f41441",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = \"data/Line_001.su\"          # SU file, IEEE floats, little endian\n",
    "outfile = \"data/Line_001_IEEE.sgy\"   # SEGY file, IEEE floats, big endian"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1967d649-f87c-486d-b41b-70bae47898c3",
   "metadata": {},
   "source": [
    "Let's create the seisio object to read the input SU file..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "06e80a11",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Input file: data/Line_001.su\n",
      "INFO: Assuming fixed-length traces for SU data.\n",
      "INFO: Data sample format: 4-byte IEEE floating-point.\n",
      "INFO: Input file endianess looks to be '<' (best guess).\n",
      "INFO: Byte offset of first trace relative to start of file: 0 bytes.\n",
      "INFO: Number of samples per data trace: 1501.\n",
      "INFO: Sampling interval: 2000 (unit as per SU standard).\n",
      "INFO: Delay (on first trace): 0 (unit as per SU standard).\n",
      "INFO: Number of data traces in file: 71284.\n"
     ]
    }
   ],
   "source": [
    "sin = seisio.input(infile)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe78a0b1-f13c-4a77-8fa4-149e1ab85f52",
   "metadata": {},
   "source": [
    "...and the seisio object to write the SEG-Y file in big-endian byte order using format 5 (IEEE floats). The primary textual file header should be encoded as EBCDIC."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5ae56741",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Output file: data/Line_001_IEEE.sgy\n",
      "INFO: Output number of samples per data trace: 1501.\n",
      "INFO: Output data sample format: 4-byte IEEE floating-point.\n",
      "INFO: Output file endianess set to '>'.\n",
      "INFO: Number of additional textual header records: 0.\n",
      "INFO: Byte offset of first trace relative to start of file: 3600 bytes.\n",
      "INFO: Number of trailer stanza records: 0.\n",
      "INFO: SEG-Y trace header extension 1 is not present.\n",
      "INFO: Number of user-defined trace headers: 0\n",
      "INFO: Creating file according to SEG-Y rev. 1.0.\n"
     ]
    }
   ],
   "source": [
    "sout = seisio.output(outfile, ns=sin.ns, vsi=sin.vsi, endian=\">\", format=5, txtenc=\"ebcdic\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42e4fdb6",
   "metadata": {},
   "source": [
    "SEG-Y files require (at least) a primary textual file header (3200 bytes) and a binary file header (400 bytes). We can get templates and fill them in ourselves, or we let seisio create default (minimal) file headers for us similar to SU's \"segyhdrs\" program."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "336275f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "textual_template = sout.txthead_template\n",
    "binary_template = sout.binhead_template"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58629aa8-f3c8-4125-bd60-f59b21e028c7",
   "metadata": {},
   "source": [
    "We could now modify or update those templates and use them for the output SEG-Y file. However, here we let seisio create default headers. In this case, we have no arguments for the *init()* method that we need to call before actually writing any trace data. The method writes the textual and binary file headers and, where applicable, additional textual header records. Here, we have no additional header records."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "d6ed136b-0321-46dc-9d57-fb54b7438202",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: SEG-Y textual file header encoding set to 'EBCDIC'.\n",
      "INFO: Wrote textual and binary file headers and 0 add. header record(s).\n"
     ]
    }
   ],
   "source": [
    "sout.init()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6126e568-f63f-4d91-9b6f-4cb62892a7ae",
   "metadata": {},
   "source": [
    "You can check the size of the output file at any point. Now that we have written the SEG-Y file headers, the file size should be 3600 bytes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "13cd8981-c9f7-4dd4-87c1-9312049b3df8",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Size of output file now 3600 bytes (should be 3600).\n"
     ]
    }
   ],
   "source": [
    "log.info(\"Size of output file now %d bytes (should be 3600).\", sout.fsize)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fdacb00-c623-470b-ba4c-3404d3c13982",
   "metadata": {},
   "source": [
    "Calling the *init()* method several times is ignored:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "52b64321-17c2-415f-89f7-8afad6b938aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: init() method called several times; call ignored.\n"
     ]
    }
   ],
   "source": [
    "sout.init()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c53aa65a-e2e5-44ff-9c0b-3fd855dfbea0",
   "metadata": {},
   "source": [
    "Now we read the whole data set from the SU file but we could obviously also loop through the data in case of very large files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b78084d0",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Reading entire file (71284 traces) from disk...\n",
      "INFO: Reading all traces took 0.1 seconds.\n"
     ]
    }
   ],
   "source": [
    "dataset = sin.read_dataset()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86bcec36-bca2-42e2-8ebc-ccfe378fe031",
   "metadata": {},
   "source": [
    "Before writing the data to disk, let's sort the data in some way (just for demonstrating the feature) in descending order:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "a953231f",
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = np.sort(dataset, order=[\"tracl\"])[::-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efd725fd-630a-4a0d-9056-1eb6af336d72",
   "metadata": {},
   "source": [
    "Now we write the data to disk (in the SEG-Y file):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "47a32180",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Mnemonic 'd1' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'f1' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'd2' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'f2' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'ungpow' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'unscale' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'ntr' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'mark' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'shortpad' dropped (not transferable without remap).\n",
      "WARNING: Mnemonic 'int64' dropped (not transferable without remap).\n",
      "INFO: Swapping bytes of output data.\n",
      "INFO: Writing 71284 trace(s) to disk...\n"
     ]
    }
   ],
   "source": [
    "nwritten = sout.write_traces(traces=dataset)\n",
    "# Some specific SU trace headers (like 'd1', 'd2', etc.) are not transferred."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "435fc3e8-72a8-44ec-90e5-b25d32dfdec4",
   "metadata": {},
   "source": [
    "Some SU-specific traces headers (like `d1` etc.) are not available in SEG-Y, i.e., those headers have been dropped. We could remap the header mnemonics to valid SEG-Y trace header mnemonics on output in case we wanted to keep the corresponding header values.\n",
    "\n",
    "Finally, we need to call the *finalize()* method. This method has to be called last, i.e., after writing the last trace data. The method writes any trailer stanza records (if applicable) and updates the binary file header to reflect the correct number of traces, header records and/or trailers in the file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "6e4f446d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Finalizing output file and re-writing updated binary header.\n",
      "INFO: Wrote a total of 71284 trace(s), file size: 445100896 bytes.\n"
     ]
    }
   ],
   "source": [
    "sout.finalize()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a6b26c4-c786-4f26-bae9-9cd7bad3d9d2",
   "metadata": {},
   "source": [
    "Attempting to write additional data to the file after calling the *finalize()* method leads to an exception:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "6fe3dfe2",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Caught 'RuntimeError' exception as expected.\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    sout.write_traces(traces=dataset)\n",
    "except RuntimeError:\n",
    "    log.info(\"Caught 'RuntimeError' exception as expected.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10b9fe56",
   "metadata": {},
   "source": [
    "The output SEGY file should have the same file size as the original 'Line_001.sgy' file. However, the content of the textual file header will be different, the data sample format will now be IEEE, the `cdp` header has been filled, the coordinate and elevation scaler has been\n",
    "zeroed, the traces are written in a different order, and some trace headers might have been lost due to the fact that SU and SEG-Y use different trace header definitions. You can check the data with the following SU commands:\n",
    "\n",
    "```\n",
    "$> segyread tape=data/Line_001_IEEE.sgy | segyclean  | surange\n",
    "71284 traces:\n",
    "tracl    1 71284 (1 - 71284)\n",
    "tracr    1 71284 (1 - 71284)\n",
    "fldr     231 481 (231 - 481)\n",
    "tracf    -1 282 (-1 - 282)\n",
    "ep       32 282 (32 - 282)\n",
    "cdp      231 481 (231 - 481)\n",
    "cdpt     1 284 (1 - 284)\n",
    "trid     0 1 (0 - 1)\n",
    "nhs      1\n",
    "counit   3\n",
    "ns       1501\n",
    "dt       2000\n",
    "gain     3\n",
    "igc      1\n",
    "afilf    207\n",
    "afils    298\n",
    "hcf      207\n",
    "hcs      298\n",
    "year     1998\n",
    "$> cat header\n",
    "...\n",
    "$> bhedtopar < binary\n",
    "jobid=0\n",
    "lino=0\n",
    "reno=0\n",
    "ntrpr=0\n",
    "nart=0\n",
    "hdt=2000\n",
    "dto=0\n",
    "hns=1501\n",
    "nso=0\n",
    "format=5\n",
    "...\n",
    "$> segyread tape=data/Line_001.sgy | sumax\n",
    "5.109500e+03 -1.546142e+03\n",
    "$> segyread tape=data/Line_001_IEEE.sgy | sumax\n",
    "5.109500e+03 -1.546142e+03\n",
    "$>\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "457c1efc-19d3-4563-b63f-e340f0fc8446",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "executable": "/usr/bin/env python3",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
