diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c64b0da6d41da5f89a4c50e478644de73d370f07..520db657d549175feb23856dc0a8f1008c8c8e47 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,8 +3,8 @@ before_script:
   # uncomment first time
   #- rm -rf TestFiles
   #- git submodule update --init
-  - git submodule sync
-  - git submodule update
+  #- git submodule sync
+  #- git submodule update
 
 
 test-3.4:
@@ -12,6 +12,7 @@ test-3.4:
   script:
   #- python3 setup.py test
   - pip3 install pytest
+  - pip3 install mock
   - python3 -m pytest --cov=wetb
   tags:
   - python
diff --git a/requirements.txt b/requirements.txt
index 270f82f988f5d487fea5e0254aa94e285e2aedc4..458306efad3e123f6c3326b9edb34d72456bd4b1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -19,4 +19,5 @@ PyScaffold
 pytest-cov
 sshtunnel
 xlsxwriter
+mock
 
diff --git a/wetb/hawc2/ae_file.py b/wetb/hawc2/ae_file.py
index 4557bb037a3e9183c14d03e33dd6cfb1b82a866e..63209c6412d552c484016b2621dbd12c8692ddfe 100644
--- a/wetb/hawc2/ae_file.py
+++ b/wetb/hawc2/ae_file.py
@@ -1,8 +1,3 @@
-'''
-Created on 24/04/2014
-
-@author: MMPE
-'''
 from __future__ import print_function
 from __future__ import unicode_literals
 from __future__ import division
@@ -11,42 +6,54 @@ from io import open
 from builtins import range
 from builtins import int
 from future import standard_library
+import os
 standard_library.install_aliases()
-
 import numpy as np
 
+
 class AEFile(object):
-    """Read HAWC2 AE (aerodynamic blade layout) file
+
+    """Read and write the HAWC2 AE (aerodynamic blade layout) file
 
     examples
     --------
     >>> aefile = AEFile(r"tests/test_files/NREL_5MW_ae.txt")
-    >>> print (aefile.thickness(36)) # Interpolated thickness at radius 36
+    >>> aefile.thickness(36) # Interpolated thickness at radius 36
     23.78048780487805
-    >>> print (aefile.chord(36)) # Interpolated chord at radius 36
+    >>> aefile.chord(36) # Interpolated chord at radius 36
     3.673
-    >>> print (aefile.pc_set_nr(36)) # pc set number at radius 36
+    >>> aefile.pc_set_nr(36) # pc set number at radius 36
     1
+    >>> ae= AEFile()
+        ae.add_set(radius=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
+                   chord=[1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
+                   thickness=[100.0, 100.0, 90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0],
+                   pc_set_id=[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
+    >>> str(ae)
+    1 r[m]           Chord[m]    T/C[%]  Set no.
+    1 11
+    0.00000000000000000e+00   1.10000000000000009e+00   1.00000000000000000e+02     1
+    1.00000000000000006e-01   1.00000000000000000e+00   1.00000000000000000e+02     1
+    2.00000000000000011e-01   9.00000000000000022e-01   9.00000000000000000e+01     1
+    2.99999999999999989e-01   8.00000000000000044e-01   8.00000000000000000e+01     1
+    4.00000000000000022e-01   6.99999999999999956e-01   7.00000000000000000e+01     1
+    5.00000000000000000e-01   5.99999999999999978e-01   6.00000000000000000e+01     1
+    5.99999999999999978e-01   5.00000000000000000e-01   5.00000000000000000e+01     1
+    6.99999999999999956e-01   4.00000000000000022e-01   4.00000000000000000e+01     1
+    8.00000000000000044e-01   2.99999999999999989e-01   3.00000000000000000e+01     1
+    9.00000000000000022e-01   2.00000000000000011e-01   2.00000000000000000e+01     1
+    1.00000000000000000e+00   1.00000000000000006e-01   1.00000000000000000e+01     1
     """
-    def __init__(self, filename):
-        with open (filename) as fid:
-            lines = fid.readlines()
-        nsets = int(lines[0].split()[0])
-        lptr = 1
-        self.ae_sets = {}
-        for _ in range(1, nsets + 1):
-            for _ in range(nsets):
-                set_nr, n_rows = [int(v) for v in lines[lptr ].split()[:2]]
-                lptr += 1
-                data = np.array([[float(v) for v in l.split()[:4]] for l in lines[lptr:lptr + n_rows]])
-                self.ae_sets[set_nr] = data
-                lptr += n_rows
 
+    def __init__(self, filename=None):
+        self.ae_sets = {}
+        if filename is not None:
+            self._read_file(filename)
 
     def _value(self, radius, column, set_nr=1):
         ae_data = self.ae_sets[set_nr]
         if radius is None:
-            return ae_data[:,column]
+            return ae_data[:, column]
         else:
             return np.interp(radius, ae_data[:, 0], ae_data[:, column])
 
@@ -55,14 +62,14 @@ class AEFile(object):
 
     def thickness(self, radius=None, set_nr=1):
         return self._value(radius, 2, set_nr)
-    
+
     def radius_ae(self, radius=None, set_nr=1):
-        radii = self.ae_sets[set_nr][:,0]
+        radii = self.ae_sets[set_nr][:, 0]
         if radius:
-            return radii[np.argmin(np.abs(radii-radius))]
+            return radii[np.argmin(np.abs(radii - radius))]
         else:
             return radii
-        
+
     def pc_set_nr(self, radius, set_nr=1):
         ae_data = self.ae_sets[set_nr]
         index = np.searchsorted(ae_data[:, 0], radius)
@@ -72,13 +79,59 @@ class AEFile(object):
             raise NotImplementedError
         return setnrs[0]
 
+    def add_set(self, radius, chord, thickness, pc_set_id, set_id=None):
+        '''This method will add another set to the ae data'''
+        if set_id is None:
+            set_id = 1
+            while set_id in self.ae_sets.keys():
+                set_id += 1
+        self.ae_sets[set_id] = np.array([radius, chord, thickness, pc_set_id]).T
+        return set_id
+
+    def __str__(self):
+        '''This method will create a string that is formatted like an ae file with the data in this class'''
+        n_sets = len(self.ae_sets)
+        retval = str(n_sets) + ' r[m]           Chord[m]    T/C[%]  Set no.\n'
+        for st_idx, st in self.ae_sets.items():
+            retval += str(st_idx) + ' ' + str(len(st)) + '\n'
+            for line in st:
+                retval += '%25.17e %25.17e %25.17e %5d\n' % (line[0], line[1], line[2], line[3])
+        return retval
+
+    def save(self, filename):
+        if not os.path.isdir(os.path.dirname(filename)):
+            os.makedirs(os.path.dirname(filename))
+        with open(filename, 'w') as fid:
+            fid.write(str(self))
+
+    def _read_file(self, filename):
+        ''' This method will read in the ae data from a HAWC2 ae file'''
+        with open(filename) as fid:
+            lines = fid.readlines()
+        nsets = int(lines[0].split()[0])
+        lptr = 1
+        self.ae_sets = {}
+        for _ in range(1, nsets + 1):
+            for _ in range(nsets):
+                set_nr, n_rows = [int(v) for v in lines[lptr].split()[:2]]
+                lptr += 1
+                data = np.array([[float(v) for v in l.split()[:4]] for l in lines[lptr:lptr + n_rows]])
+                self.ae_sets[set_nr] = data
+                lptr += n_rows
 
 
+def main():
+    if __name__ == "__main__":
+        ae = AEFile(os.path.dirname(__file__) + "/tests/test_files/NREL_5MW_ae.txt")
+        print(ae.radius_ae(36))
+        print(ae.thickness())
+        print(ae.chord(36))
+        print(ae.pc_set_nr(36))
+        ae.add_set(radius=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
+                   chord=[1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
+                   thickness=[100.0, 100.0, 90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0],
+                   pc_set_id=[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
+        print(str(ae))
 
 
-if __name__ == "__main__":
-    ae = AEFile(r"tests/test_files/NREL_5MW_ae.txt")
-    print (ae.radius_ae(36))
-    print (ae.thickness())
-    print (ae.chord(36))
-    print (ae.pc_set_nr(36))
+main()
diff --git a/wetb/hawc2/tests/test_ae_file.py b/wetb/hawc2/tests/test_ae_file.py
index 4e57189110f99d4f914a352f9805d32971532b73..af1d5f0769465d47b6d5c60535db2f589b35a9dc 100644
--- a/wetb/hawc2/tests/test_ae_file.py
+++ b/wetb/hawc2/tests/test_ae_file.py
@@ -3,20 +3,28 @@ Created on 05/11/2015
 
 @author: MMPE
 '''
-from __future__ import unicode_literals
-from __future__ import print_function
-from __future__ import division
 from __future__ import absolute_import
-from future import standard_library
-standard_library.install_aliases()
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import os
 import unittest
+
+from future import standard_library
+import mock
+
+from wetb.hawc2 import ae_file
 from wetb.hawc2.ae_file import AEFile
-import os
+import numpy as np
+
+standard_library.install_aliases()
 
 testfilepath = os.path.join(os.path.dirname(__file__), 'test_files/')  # test file path
-class TestAEFile(unittest.TestCase):
 
 
+class TestAEFile(unittest.TestCase):
+
     def test_aefile(self):
         ae = AEFile(testfilepath + "NREL_5MW_ae.txt")
         self.assertEqual(ae.thickness(38.950), 21)
@@ -29,7 +37,52 @@ class TestAEFile(unittest.TestCase):
         self.assertEqual(ae.chord(32), 3.673)
         self.assertEqual(ae.pc_set_nr(32), 1)
 
+    def test_ae_file_main(self):
+        def no_print(s):
+            pass
+        with mock.patch.object(ae_file, "__name__", "__main__"):
+            with mock.patch.object(ae_file, "print", no_print):
+                getattr(ae_file, 'main')()
+
+    def test_add_set(self):
+        ae = AEFile(testfilepath + "NREL_5MW_ae.txt")
+
+        ae.add_set(radius=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
+                   chord=[1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
+                   thickness=[100.0, 100.0, 90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0],
+                   pc_set_id=[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
+
+        ae.add_set(radius=[0.0, 0.1],
+                   chord=[1.1, 1.0],
+                   thickness=[100.0, 100.0],
+                   pc_set_id=[1.0, 1.0],
+                   set_id=4)
+
+        self.assertEqual(ae.thickness(38.950), 21)
+        self.assertEqual(ae.chord(38.950), 3.256)
+        self.assertEqual(ae.pc_set_nr(38.950), 1)
+        np.testing.assert_array_equal(ae.chord(None, 2), [1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1])
+        np.testing.assert_array_equal(ae.ae_sets[2][:2], ae.ae_sets[4])
+
+    def test_str(self):
+        ae = AEFile(testfilepath + "NREL_5MW_ae.txt")
+        ref = """1 r[m]           Chord[m]    T/C[%]  Set no.
+1 19
+  0.00000000000000000e+00   3.54199999999999982e+00   1.00000000000000000e+02     1"""
+
+        self.assertEqual(str(ae)[:len(ref)], ref)
+
+    def test_save(self):
+        ae = AEFile()
 
+        ae.add_set(radius=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
+                   chord=[1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
+                   thickness=[100.0, 100.0, 90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0],
+                   pc_set_id=[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
+        fn = testfilepath + "tmp/ae_file.txt"
+        ae.save(fn)
+        ae2 = AEFile(fn)
+        assert str(ae) == str(ae2)
 
 
 if __name__ == "__main__":