From 70d9b0ad8ec47fdd2ad6412e536a2cb9cac031b4 Mon Sep 17 00:00:00 2001
From: acpaquette <acp263@nau.edu>
Date: Thu, 3 May 2018 06:25:20 -0700
Subject: [PATCH] Ipf Writer (#37)

* Added to ipf from dataframe. Also updated both gpf and ipf writer tests

* Added test output file.

* Added asserts to gpf and ipf tests

* Reverted save_gpf testing to numpy array almost equals
---
 notebooks/Socet2ISIS.ipynb                    | 181 +++--
 plio/io/io_bae.py                             |  51 +-
 .../tests/temp/P20_008845_1894_XN_09N203W.ipf | 729 ++++++++++++++++++
 plio/io/tests/test_io_bae.py                  |  39 +-
 4 files changed, 917 insertions(+), 83 deletions(-)
 create mode 100644 plio/io/tests/temp/P20_008845_1894_XN_09N203W.ipf

diff --git a/notebooks/Socet2ISIS.ipynb b/notebooks/Socet2ISIS.ipynb
index 04b6b2c..636ba38 100644
--- a/notebooks/Socet2ISIS.ipynb
+++ b/notebooks/Socet2ISIS.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 2,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -15,12 +15,12 @@
     "import numpy as np\n",
     "\n",
     "from plio.examples import get_path\n",
-    "from plio.io.io_bae import read_gpf"
+    "from plio.io.io_bae import read_gpf, read_ipf"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -69,80 +69,7 @@
     "        # Sets the value of PATH to the path of the ATF file\n",
     "        files_dict['PATH'] = os.path.dirname(os.path.abspath(atf_file))\n",
     "        \n",
-    "        return files_dict\n",
-    "    \n",
-    "@singledispatch\n",
-    "def read_ipf(arg):\n",
-    "    return str(arg)\n",
-    "\n",
-    "@read_ipf.register(str)\n",
-    "def read_ipf_str(input_data):\n",
-    "    \"\"\"\n",
-    "    Read a socet ipf file into a pandas data frame\n",
-    "\n",
-    "    Parameters\n",
-    "    ----------\n",
-    "    input_data : str\n",
-    "                 path to the an input data file\n",
-    "\n",
-    "    Returns\n",
-    "    -------\n",
-    "    df : pd.DataFrame\n",
-    "         containing the ipf data with appropriate column names and indices\n",
-    "    \"\"\"\n",
-    "\n",
-    "    # Check that the number of rows is matching the expected number\n",
-    "    with open(input_data, 'r') as f:\n",
-    "        for i, l in enumerate(f):\n",
-    "            if i == 1:\n",
-    "                cnt = int(l)\n",
-    "            elif i == 2:\n",
-    "                col = l\n",
-    "                break\n",
-    "                \n",
-    "    columns = np.genfromtxt(input_data, skip_header=2, dtype='unicode',\n",
-    "                            max_rows = 1, delimiter = ',')\n",
-    "\n",
-    "    # TODO: Add unicode conversion\n",
-    "    d = [line.split() for line in open(input_data, 'r')]\n",
-    "    d = np.hstack(np.array(d[3:]))\n",
-    "    \n",
-    "    d = d.reshape(-1, 12)\n",
-    "    \n",
-    "    df = pd.DataFrame(d, columns=columns)\n",
-    "    file = os.path.split(os.path.splitext(input_data)[0])[1]\n",
-    "    df['ipf_file'] = pd.Series(np.full((len(df['pt_id'])), file), index = df.index)\n",
-    "\n",
-    "    assert int(cnt) == len(df), 'Dataframe length {} does not match point length {}.'.format(int(cnt), len(df))\n",
-    "    \n",
-    "    # Soft conversion of numeric types to numerics, allows str in first col for point_id\n",
-    "    df = df.apply(pd.to_numeric, errors='ignore')\n",
-    "\n",
-    "    return df\n",
-    "\n",
-    "@read_ipf.register(list)\n",
-    "def read_ipf_list(input_data_list):\n",
-    "    \"\"\"\n",
-    "    Read a socet ipf file into a pandas data frame\n",
-    "\n",
-    "    Parameters\n",
-    "    ----------\n",
-    "    input_data_list : list\n",
-    "                      list of paths to the a set of input data files\n",
-    "\n",
-    "    Returns\n",
-    "    -------\n",
-    "    df : pd.DataFrame\n",
-    "         containing the ipf data with appropriate column names and indices\n",
-    "    \"\"\"\n",
-    "    frames = []\n",
-    "\n",
-    "    for input_file in input_data_list:\n",
-    "        frames.append(read_ipf(input_file))\n",
-    "\n",
-    "    df = pd.concat(frames)\n",
-    "\n",
-    "    return df"
+    "        return files_dict"
    ]
   },
   {
@@ -2019,6 +1946,106 @@
     "new_df"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "@singledispatch\n",
+    "def read_ipf(arg):\n",
+    "    return str(arg)\n",
+    "\n",
+    "@read_ipf.register(str)\n",
+    "def read_ipf_str(input_data):\n",
+    "    \"\"\"\n",
+    "    Read a socet ipf file into a pandas data frame\n",
+    "\n",
+    "    Parameters\n",
+    "    ----------\n",
+    "    input_data : str\n",
+    "                 path to the an input data file\n",
+    "\n",
+    "    Returns\n",
+    "    -------\n",
+    "    df : pd.DataFrame\n",
+    "         containing the ipf data with appropriate column names and indices\n",
+    "    \"\"\"\n",
+    "\n",
+    "    # Check that the number of rows is matching the expected number\n",
+    "    with open(input_data, 'r') as f:\n",
+    "        for i, l in enumerate(f):\n",
+    "            if i == 1:\n",
+    "                cnt = int(l)\n",
+    "            elif i == 2:\n",
+    "                col = l\n",
+    "                break\n",
+    "                \n",
+    "    columns = np.genfromtxt(input_data, skip_header=2, dtype='unicode',\n",
+    "                            max_rows = 1, delimiter = ',')\n",
+    "\n",
+    "    # TODO: Add unicode conversion\n",
+    "    d = [line.split() for line in open(input_data, 'r')]\n",
+    "    d = np.hstack(np.array(d[3:]))\n",
+    "    \n",
+    "    d = d.reshape(-1, 12)\n",
+    "    \n",
+    "    df = pd.DataFrame(d, columns=columns)\n",
+    "    file = os.path.split(os.path.splitext(input_data)[0])[1]\n",
+    "    df['ipf_file'] = pd.Series(np.full((len(df['pt_id'])), file), index = df.index)\n",
+    "\n",
+    "    assert int(cnt) == len(df), 'Dataframe length {} does not match point length {}.'.format(int(cnt), len(df))\n",
+    "    \n",
+    "    # Soft conversion of numeric types to numerics, allows str in first col for point_id\n",
+    "    df = df.apply(pd.to_numeric, errors='ignore')\n",
+    "\n",
+    "    return df\n",
+    "\n",
+    "@read_ipf.register(list)\n",
+    "def read_ipf_list(input_data_list):\n",
+    "    \"\"\"\n",
+    "    Read a socet ipf file into a pandas data frame\n",
+    "\n",
+    "    Parameters\n",
+    "    ----------\n",
+    "    input_data_list : list\n",
+    "                      list of paths to the a set of input data files\n",
+    "\n",
+    "    Returns\n",
+    "    -------\n",
+    "    df : pd.DataFrame\n",
+    "         containing the ipf data with appropriate column names and indices\n",
+    "    \"\"\"\n",
+    "    frames = []\n",
+    "\n",
+    "    for input_file in input_data_list:\n",
+    "        frames.append(read_ipf(input_file))\n",
+    "\n",
+    "    df = pd.concat(frames)\n",
+    "\n",
+    "    return df"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "True\n"
+     ]
+    }
+   ],
+   "source": [
+    "x = np.array(['1', '2', '3'])\n",
+    "y = np.array(['1', '2', '3'])\n",
+    "\n",
+    "print((x == y).all())"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/plio/io/io_bae.py b/plio/io/io_bae.py
index c69ddc8..37e5abc 100644
--- a/plio/io/io_bae.py
+++ b/plio/io/io_bae.py
@@ -85,11 +85,10 @@ def read_ipf_str(input_data):
     columns = np.genfromtxt(input_data, skip_header=2, dtype='unicode',
                             max_rows = 1, delimiter = ',')
 
-    # TODO: Add unicode conversion
     d = [line.split() for line in open(input_data, 'r')]
     d = np.hstack(np.array(d[3:]))
 
-    d = d.reshape(-1, 12)
+    d = d.reshape(-1, 12).astype('unicode')
 
     df = pd.DataFrame(d, columns=columns)
     file = os.path.split(os.path.splitext(input_data)[0])[1]
@@ -126,6 +125,54 @@ def read_ipf_list(input_data_list):
 
     return df
 
+def save_ipf(df, output_path):
+    """
+    Write a socet gpf file from a gpf-defined pandas dataframe
+
+    Parameters
+    ----------
+    df          : pd.DataFrame
+                  Pandas DataFrame
+
+    output_file : str
+                  path to the output data file
+
+    Returns
+    -------
+    int         : success value
+                  0 = success, 1 = errors
+    """
+
+    for ipf_file, ipf_df in df.groupby('ipf_file'):
+
+        output_file = os.path.join(output_path, ipf_file + '.ipf')
+
+        # Check that file can be opened
+        try:
+            outIPF = open(output_file, 'w', newline='\r\n')
+        except:
+            print('Unable to open output ipf file: {0}'.format(output_file))
+            return 1
+
+        #grab number of rows in pandas dataframe ipf group
+        numpts = len(ipf_df)
+
+        #Output ipf header
+        outIPF.write('IMAGE POINT FILE\n')
+        outIPF.write('{0}\n'.format(numpts))
+        outIPF.write('pt_id,val,fid_val,no_obs,l.,s.,sig_l,sig_s,res_l,res_s,fid_x,fid_y\n')
+
+        for index, row in ipf_df.iterrows():
+            #Output coordinates to ipf file
+            outIPF.write('{0} {1} {2} {3}\n'.format(row['pt_id'], row['val'], row['fid_val'], row['no_obs']))
+            outIPF.write('{:0.6f}  {:0.6f}\n'.format(row['l.'], row['s.']))
+            outIPF.write('{:0.6f}  {:0.6f}\n'.format(row['sig_l'], row['sig_s']))
+            outIPF.write('{:0.6f}  {:0.6f}\n'.format(row['res_l'], row['res_s']))
+            outIPF.write('{:0.6f}  {:0.6f}\n\n'.format(row['fid_x'], row['fid_y']))
+
+        outIPF.close()
+    return
+
 def read_gpf(input_data):
     """
     Read a socet gpf file into a pandas data frame
diff --git a/plio/io/tests/temp/P20_008845_1894_XN_09N203W.ipf b/plio/io/tests/temp/P20_008845_1894_XN_09N203W.ipf
new file mode 100644
index 0000000..4a377c8
--- /dev/null
+++ b/plio/io/tests/temp/P20_008845_1894_XN_09N203W.ipf
@@ -0,0 +1,729 @@
+IMAGE POINT FILE
+121
+pt_id,val,fid_val,no_obs,l.,s.,sig_l,sig_s,res_l,res_s,fid_x,fid_y
+1_8344_8845_4r 1 0 0
+-4058.982422  -2318.010742
+0.000000  0.000000
+-0.062556  -0.214713
+0.000000  0.000000
+
+2_8344_8845_4r 1 0 0
+-3969.065186  -606.849243
+0.000000  0.000000
+0.228660  0.105249
+0.000000  0.000000
+
+3_8344_8845_4r_mt_z 1 0 0
+-1019.739014  -2300.877197
+0.000000  0.000000
+-0.025129  -0.002447
+0.000000  0.000000
+
+4_8344_8845_4r_mt_z 1 0 0
+-1037.099121  -548.180237
+0.000000  0.000000
+-0.000756  0.227752
+0.000000  0.000000
+
+5_8344_8845_4r 1 0 0
+2438.984131  -2304.843506
+0.000000  0.000000
+0.062022  -0.109977
+0.000000  0.000000
+
+6_8344_8845_4r 1 0 0
+2397.826904  -562.432861
+0.000000  0.000000
+-0.072678  -0.056104
+0.000000  0.000000
+
+7_8344_8845_4r_mt_z 1 0 0
+-2510.927734  -1267.364868
+0.000000  0.000000
+0.215250  -0.040427
+0.000000  0.000000
+
+8_8344-8845_4r_mt_z 1 0 0
+840.825317  -1028.345337
+0.000000  0.000000
+-0.241922  0.382924
+0.000000  0.000000
+
+9_8344_8845_4r 1 0 0
+-4070.962158  2465.817139
+0.000000  0.000000
+-0.140837  0.005980
+0.000000  0.000000
+
+10_8344_8845_4r 1 0 0
+-4044.697510  1008.950928
+0.000000  0.000000
+0.063678  0.661294
+0.000000  0.000000
+
+11_8344_8845_4r 1 0 0
+-761.216064  2303.787109
+0.000000  0.000000
+-0.247307  -0.587299
+0.000000  0.000000
+
+12_8344_8845_4r 1 0 0
+-889.364441  966.533997
+0.000000  0.000000
+-0.251753  0.008170
+0.000000  0.000000
+
+13_8344_8845_4r 1 0 0
+-2559.871338  1777.522827
+0.000000  0.000000
+-0.131265  -0.305102
+0.000000  0.000000
+
+14_8344_8845_4r 1 0 0
+2385.278320  2476.032227
+0.000000  0.000000
+0.389532  -0.299258
+0.000000  0.000000
+
+15_8344_8845_4r_mt_z 1 0 0
+2395.869385  1038.165405
+0.000000  0.000000
+-0.170850  0.372485
+0.000000  0.000000
+
+16_8344_8845_4r 1 0 0
+756.099792  1785.494751
+0.000000  0.000000
+0.165338  -0.327408
+0.000000  0.000000
+
+17_8344_8845_2r_mt_z 1 0 0
+-3138.269531  442.515503
+0.000000  0.000000
+-0.023370  -0.248643
+0.000000  0.000000
+
+18_8344_8845_2r 1 0 0
+-1773.864990  354.084259
+0.000000  0.000000
+-0.002223  -0.000684
+0.000000  0.000000
+
+19_8344_8845_2r_mt_z 1 0 0
+-92.482826  723.305237
+0.000000  0.000000
+-0.214498  0.145192
+0.000000  0.000000
+
+20_8344_8845_2r_mt_z 1 0 0
+1434.079712  742.064026
+0.000000  0.000000
+-0.058132  -0.171782
+0.000000  0.000000
+
+21_8344_8845_4r_xyz 1 0 0
+-838.991028  -614.524109
+0.000000  0.000000
+-0.131313  0.997120
+0.000000  0.000000
+
+22_8344_8845_4r_mt_z 1 0 0
+-3994.073975  -2160.606445
+0.000000  0.000000
+0.217774  -0.141372
+0.000000  0.000000
+
+23_8344_8845_4r_mt_z 1 0 0
+-3851.864990  2088.046875
+0.000000  0.000000
+-0.078440  -0.221650
+0.000000  0.000000
+
+24_8344_8845_4r_mt_z 1 0 0
+2343.634033  -2073.817871
+0.000000  0.000000
+-0.274344  0.067791
+0.000000  0.000000
+
+25_8344_8845_4r_mt_z 1 0 0
+2350.053711  2168.792236
+0.000000  0.000000
+-0.311081  -0.152226
+0.000000  0.000000
+
+26_8344_8845_4r_mt_z 1 0 0
+-1844.550781  -996.016479
+0.000000  0.000000
+-0.108472  0.122981
+0.000000  0.000000
+
+27_8344_8845_2r_mt_z 1 0 0
+-1618.005371  700.699158
+0.000000  0.000000
+-0.020846  0.073456
+0.000000  0.000000
+
+28_8344_8845_4r_mt_z 1 0 0
+521.921509  -1602.441406
+0.000000  0.000000
+-0.009861  0.363227
+0.000000  0.000000
+
+29_8344_8845_4r_mt_z 1 0 0
+820.691284  1469.345459
+0.000000  0.000000
+-0.664959  -0.066244
+0.000000  0.000000
+
+30_8344_8845_3r_mt_z 1 0 0
+-326.405365  -283.346985
+0.000000  0.000000
+-0.206811  0.180573
+0.000000  0.000000
+
+61_8344_8845_4r_mt_z 1 0 0
+-4067.466064  -2193.302002
+0.000000  0.000000
+-0.017458  -0.229608
+0.000000  0.000000
+
+62_8344_8845_4r_mt_z 1 0 0
+2040.637939  2052.019043
+0.000000  0.000000
+0.187054  -0.199539
+0.000000  0.000000
+
+63_8344_8845_4r_mt_z 1 0 0
+2267.361328  -1402.644897
+0.000000  0.000000
+-0.259674  -0.350489
+0.000000  0.000000
+
+65_8344_8845_4r_mt_z 1 0 0
+-675.820618  1659.593628
+0.000000  0.000000
+0.285702  -0.673177
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_3 1 0 1
+-3543.180176  -2052.497559
+0.099990  0.099990
+-0.271723  0.046268
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_5 1 0 1
+-3693.414551  118.131378
+0.191225  0.191225
+-0.007535  0.000003
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_8 1 0 1
+-3529.115479  1634.993530
+0.010654  0.010654
+-0.112990  0.190108
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_9 1 0 1
+-1530.085083  -2021.120728
+0.025998  0.025998
+-0.287801  -0.050820
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_10 1 0 1
+-1163.659546  -2110.948730
+0.054246  0.054246
+-0.209774  -0.028915
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_11 1 0 1
+-649.603027  -291.606293
+0.144968  0.144968
+0.179422  0.480350
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_12 1 0 1
+-1879.115479  1650.314575
+0.044342  0.044342
+0.194544  -0.551285
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_13 1 0 1
+1195.076782  -2043.631714
+0.081316  0.081316
+-0.184309  0.153021
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_14 1 0 1
+1826.979736  -2180.584961
+0.185789  0.185789
+0.208304  -0.026378
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_15 1 0 1
+1833.592407  -1740.516968
+0.238122  0.238122
+0.652892  -0.509659
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_16 1 0 1
+1370.180664  -273.589996
+0.113241  0.113241
+0.296132  -0.060485
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_17 1 0 1
+1198.482544  -429.786133
+0.055307  0.055307
+-0.091967  0.108114
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_18 1 0 1
+1516.067993  1830.024048
+0.009269  0.009269
+-0.002093  -0.264173
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_19 1 0 1
+1338.967651  1679.986084
+0.004901  0.004901
+-0.030115  -0.306342
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_20 1 0 1
+1350.758423  1952.026978
+0.019970  0.019970
+-0.011408  -0.409686
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_1 1 0 0
+-3224.000000  -2003.000000
+0.000000  0.000000
+0.055124  0.018517
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_2 1 0 0
+-3389.000000  -2155.000000
+0.000000  0.000000
+-0.073150  -0.271173
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_3 1 0 0
+-2913.000000  -2000.000000
+0.000000  0.000000
+-0.088180  -0.049593
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_4 1 0 1
+-3226.000000  167.000000
+0.000000  0.000000
+-0.195774  -0.000066
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_5 1 0 1
+-2934.000000  -6.000000
+0.000000  0.000000
+-0.049005  0.437424
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_6 1 0 3
+-3378.000000  1532.000000
+0.000000  0.000000
+0.026541  0.063346
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_7 1 0 3
+-3378.000000  1672.000000
+0.000000  0.000000
+0.055623  0.013456
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_8 1 0 3
+-2793.000000  1837.000000
+0.000000  0.000000
+-0.117483  -0.229337
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_9 1 0 0
+-780.000000  -1953.000000
+0.000000  0.000000
+0.298743  -0.045963
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_10 1 0 2
+423.000000  -1995.000000
+0.000000  0.000000
+0.067585  0.401377
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_11 1 0 1
+-21.000000  196.000000
+0.000000  0.000000
+0.069550  -0.000458
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_12 1 0 1
+2885.000000  -2124.000000
+0.000000  0.000000
+0.254136  -0.273798
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_13 1 0 1
+2746.000000  -2253.000000
+0.000000  0.000000
+-0.407167  -0.176964
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_14 1 0 0
+2728.000000  -1980.000000
+0.000000  0.000000
+-0.885848  0.137668
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_15 0 0 0
+2942.000000  58.000000
+0.000000  0.000000
+0.000000  0.000000
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_16 1 0 2
+2865.000000  2024.000000
+0.000000  0.000000
+-0.053859  0.035981
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_17 1 0 2
+3175.000000  1974.000000
+0.000000  0.000000
+-0.064058  0.044374
+0.000000  0.000000
+
+P20_008845_1894_XN_09N203W_18 1 0 2
+2872.000000  1565.000000
+0.000000  0.000000
+0.256228  0.218860
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_49 1 0 1
+-2629.182861  1085.034424
+0.012761  0.012761
+0.208403  -0.004282
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_54 1 0 1
+-1095.406738  1127.088013
+0.274421  0.274421
+0.019106  -0.331897
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_55 1 0 1
+-941.496277  1247.825806
+0.055631  0.055631
+0.152919  -0.306029
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_56 1 0 1
+-1098.958984  1441.816895
+0.114842  0.114842
+-0.297223  -0.308728
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_63 1 0 1
+119.944458  1116.177612
+0.023727  0.023727
+-0.104057  -0.034587
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_64 1 0 1
+-19.255381  1270.651611
+0.007022  0.007022
+-0.294970  -0.136646
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_65 1 0 1
+-271.636139  1030.269287
+0.141314  0.141314
+-0.007378  0.127183
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_71 1 0 1
+1793.756836  1419.468140
+0.070811  0.070811
+0.008127  -0.059651
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_77 1 0 1
+3770.185547  1056.433594
+0.051015  0.051015
+-0.344149  0.791881
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_3 1 0 0
+-819.994568  -476.940125
+0.000000  0.000000
+-0.010086  0.238933
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_4 1 0 0
+-1038.745972  -225.617737
+0.000000  0.000000
+-0.102515  0.293944
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_5 1 0 0
+-1043.086548  -229.290588
+0.000000  0.000000
+-0.103618  0.222174
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_6 1 0 0
+-1016.667114  -212.669418
+0.000000  0.000000
+0.098336  0.182504
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_7 1 0 0
+-1089.852539  -179.613083
+0.000000  0.000000
+-0.099015  0.247487
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_43 1 0 1
+231.430023  1286.035034
+0.179721  0.179721
+0.043216  0.007602
+0.000000  0.000000
+
+P01_001540_1889_XI_08N204W_44 1 0 1
+53.370300  1130.200195
+0.035373  0.035373
+-0.239021  0.051970
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_20 1 0 1
+-3490.634277  -1071.889893
+0.074986  0.074986
+-0.109513  0.027899
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_21 1 0 1
+-3489.029297  -1344.598267
+0.117221  0.117221
+0.119840  -0.073966
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_26 1 0 1
+-2843.921875  -1365.052490
+0.066368  0.066368
+0.053526  -0.129321
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_27 1 0 1
+-2872.278076  -1055.845581
+0.044944  0.044944
+0.014887  -0.175307
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_32 1 0 1
+-702.726318  -1309.760742
+0.097152  0.097152
+-0.121270  0.083388
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_33 1 0 1
+-425.879700  -1332.264404
+0.141272  0.141272
+0.278120  0.018378
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_39 1 0 1
+957.507324  -1314.205933
+0.214219  0.214219
+-0.088346  0.135983
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_40 1 0 1
+1286.863525  -1325.946045
+0.022701  0.022701
+0.025672  -0.015907
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_41 1 0 1
+1415.343628  -1585.812134
+0.062944  0.062944
+0.178247  0.100219
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_42 1 0 1
+-713.122681  -1899.271973
+0.109711  0.109711
+-0.247557  0.240463
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_48 1 0 1
+2357.769287  -1605.211670
+0.142259  0.142259
+-0.046652  -0.341859
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_49 1 0 1
+2368.677490  -1310.253662
+0.084816  0.084816
+0.168448  -0.178884
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_50 1 0 1
+2938.904541  -1286.650635
+0.268181  0.268181
+0.222150  -0.289282
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_41 1 0 1
+-2964.822021  -752.729980
+0.130511  0.130511
+0.199895  0.181932
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_42 1 0 1
+-2676.941162  -549.997925
+0.015523  0.015523
+-0.189075  0.282047
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_43 1 0 1
+-2503.684570  -1243.333618
+0.091619  0.091619
+-0.183131  -0.034143
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_46 1 0 1
+-984.080139  -1301.115845
+0.028430  0.028430
+-0.103870  -0.014166
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_47 1 0 1
+-1119.626953  -926.132080
+0.195907  0.195907
+-0.217611  0.087415
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_53 1 0 1
+3304.798340  -528.821411
+0.090225  0.090225
+-0.127036  -0.243320
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_54 1 0 1
+3597.587646  -608.987488
+0.187463  0.187463
+0.132150  -0.402642
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_55 1 0 1
+3277.619873  -1106.364136
+0.141123  0.141123
+-0.258301  -0.487463
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_64 1 0 1
+-1488.927979  306.370270
+0.141123  0.141123
+0.113540  0.000408
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_67 1 0 1
+-1501.843384  294.863434
+0.141123  0.141123
+-0.038216  -0.001066
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_68 1 0 1
+-1487.291992  301.690338
+0.141123  0.141123
+-0.161360  0.000601
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_71 1 0 1
+-1476.824463  421.302856
+0.141123  0.141123
+0.045458  0.000436
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_66 1 0 1
+-1473.926636  445.164948
+0.141123  0.141123
+-0.039173  -0.000061
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_72 1 0 1
+-1478.191040  398.059052
+0.141123  0.141123
+0.039510  -0.000569
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_74 1 0 1
+-1463.276489  270.004364
+0.141123  0.141123
+0.097608  0.000572
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_76 1 0 1
+-1399.385376  210.815338
+0.141123  0.141123
+-0.021339  -0.000335
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_82 1 0 1
+-1110.612061  -112.804382
+0.141123  0.141123
+-0.179249  0.431591
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_2 1 0 1
+-3987.065674  -1756.185791
+0.141123  0.141123
+0.018394  -0.141215
+0.000000  0.000000
+
+P19_008344_1894_XN_09N203W_7 1 0 1
+-3991.173340  1967.117554
+0.141123  0.141123
+0.242488  -0.046890
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_76 1 0 1
+4066.573730  1038.447998
+0.141123  0.141123
+-0.272976  0.967351
+0.000000  0.000000
+
+P03_002371_1888_XI_08N204W_78 1 0 1
+4083.873291  1277.689209
+0.141123  0.141123
+-0.328486  0.836286
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_19 1 0 1
+-3917.203125  -1175.195679
+0.141123  0.141123
+-0.022263  -0.151156
+0.000000  0.000000
+
+P01_001606_1897_XI_09N203W_65 1 0 1
+4070.485840  -2315.992188
+0.141123  0.141123
+-0.121370  -0.479070
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_1 1 0 0
+-1197.647949  -569.925598
+0.000000  0.000000
+-0.070627  0.194853
+0.000000  0.000000
+
+P03_002226_1895_XI_09N203W_2 1 0 0
+-1241.685791  -499.006836
+0.000000  0.000000
+-0.066482  0.270447
+0.000000  0.000000
+
diff --git a/plio/io/tests/test_io_bae.py b/plio/io/tests/test_io_bae.py
index 105680b..2817c88 100644
--- a/plio/io/tests/test_io_bae.py
+++ b/plio/io/tests/test_io_bae.py
@@ -1,10 +1,11 @@
 import json
+import os
 
 import numpy as np
 import pandas as pd
 from pandas.util.testing import assert_frame_equal
 
-from plio.io.io_bae import socetset_keywords_to_json, read_gpf, save_gpf, read_ipf
+from plio.io.io_bae import socetset_keywords_to_json, read_gpf, save_gpf, read_ipf, save_ipf
 from plio.examples import get_path
 
 import pytest
@@ -25,15 +26,42 @@ def insight_ipf():
 def insight_expected_ipf():
     return pd.read_csv(get_path('P20_008845_1894_XN_09N203W.csv'))
 
+@pytest.mark.parametrize('ipf, expected', [([insight_ipf()],insight_expected_ipf())])
+def test_read_ifp(ipf, expected):
+    df = read_ipf(ipf)
+    assert_frame_equal(df, expected)
+
 @pytest.mark.parametrize('gpf, expected', [(insight_gpf(),insight_expected_gpf())])
 def test_read_gfp(gpf, expected):
     df = read_gpf(gpf)
     assert_frame_equal(df, expected)
 
-@pytest.mark.parametrize('ipf, expected', [([insight_ipf()],insight_expected_ipf())])
-def test_read_ifp(ipf, expected):
+@pytest.mark.parametrize('ipf, file', [(insight_ipf(), 'plio/io/tests/temp')])
+def test_write_ipf(ipf, file):
     df = read_ipf(ipf)
-    assert_frame_equal(df, expected)
+    save_ipf(df, file)
+
+    file = os.path.join(file, 'P20_008845_1894_XN_09N203W.ipf')
+
+    with open(ipf) as f:
+        fl = f.readlines()
+
+    with open(file) as f:
+        fs = f.readlines()
+
+    # Check that the header is the same
+    for i in range(3):
+        assert fl[i] == fs[i]
+
+    truth_arr = [line.split() for line in open(ipf, 'r')][3:]
+    truth_arr = np.hstack(np.array(truth_arr))
+    truth_arr = truth_arr.reshape(-1, 12)
+
+    test_arr  = [line.split() for line in open(file, 'r')][3:]
+    test_arr = np.hstack(np.array(test_arr))
+    test_arr = test_arr.reshape(-1, 12)
+
+    assert (truth_arr == test_arr).all()
 
 @pytest.mark.parametrize('gpf, file', [(insight_gpf(), 'out.gpf')])
 def test_write_gpf(gpf, file):
@@ -56,8 +84,11 @@ def test_write_gpf(gpf, file):
 
     truth_arr = np.genfromtxt(gpf, skip_header=3)
     test_arr = np.genfromtxt(file, skip_header=3)
+
     np.testing.assert_array_almost_equal(truth_arr, test_arr)
 
+    # np.testing.assert_array_almost_equal(truth_arr, test_arr)
+
 def test_create_from_socet_lis():
     socetlis = get_path('socet_isd.lis')
     socetell = get_path('ellipsoid.ell')
-- 
GitLab