diff --git a/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17.out.md5 b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17.out.md5
new file mode 100644
index 0000000000000000000000000000000000000000..ad0ef41e824577999c11d33d4baec2df970975ed
--- /dev/null
+++ b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17.out.md5
@@ -0,0 +1 @@
+fbcbdd6fc11f4e74751257626ce6d03f
diff --git a/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_atomic_displacements_data_0.txt.md5 b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_atomic_displacements_data_0.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..790eae8b899411b9c1f8af49aadb9ab5993d438d
--- /dev/null
+++ b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_atomic_displacements_data_0.txt.md5
@@ -0,0 +1 @@
+5963d231bfed4a4fdc3d9a27f6903026
diff --git a/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_data.txt.md5 b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_data.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..9c0d4e946b8c531c6dfe16f732e87d75e79bdc40
--- /dev/null
+++ b/Testing/Data/UnitTest/toluene_molecule_LoadCRYSTAL17_data.txt.md5
@@ -0,0 +1 @@
+dcedfbda8976f92bc8775e1e1aa15362
diff --git a/docs/source/release/v4.3.0/indirect_geometry.rst b/docs/source/release/v4.3.0/indirect_geometry.rst
index da4c2242c5a0d8e6716d7bfa96c89aa3125fe02e..1e7455c3e72a4378db5959788c5dec1d3f50cd0d 100644
--- a/docs/source/release/v4.3.0/indirect_geometry.rst
+++ b/docs/source/release/v4.3.0/indirect_geometry.rst
@@ -9,4 +9,10 @@ Indirect Geometry Changes
     putting new features at the top of the section, followed by
     improvements, followed by bug fixes.
 
-:ref:`Release 4.3.0 <v4.3.0>`
\ No newline at end of file
+
+BugFixes
+########
+
+- The Abins file parser no longer fails to read data from non-periodic vibration calculations performed with CRYSTAL17.
+
+:ref:`Release 4.3.0 <v4.3.0>`
diff --git a/scripts/AbinsModules/GeneralAbInitioParser.py b/scripts/AbinsModules/GeneralAbInitioParser.py
index 871dfe53b38310b7fce45ebc78d983ad5d15669b..0cc3d00d42285346a2df1f760c293d34b0accf60 100644
--- a/scripts/AbinsModules/GeneralAbInitioParser.py
+++ b/scripts/AbinsModules/GeneralAbInitioParser.py
@@ -7,6 +7,7 @@
 from __future__ import (absolute_import, division, print_function)
 
 import six
+import re
 import AbinsModules
 
 
@@ -17,18 +18,40 @@ class GeneralAbInitioParser(object):
     def __init__(self):
         pass
 
-    def find_first(self, file_obj=None, msg=None):
+    def find_first(self, file_obj=None, msg=None, regex=None):
         """
         Finds the first line with msg. Moves file current position to the next line.
         :param file_obj: file object from which we read
-        :param msg: keyword to find
+        :type file_obj: BinaryIO
+        :param msg: keyword to find (exact match)
+        :type msg: str
+        :param regex: regular expression to find (use *instead of* msg option).
+            This string will be compiled to a Python re.Pattern .
+        :type regex: str
         """
         if not six.PY2:
-            msg = bytes(msg, "utf8")
-        while not self.file_end(file_obj=file_obj):
-            line = file_obj.readline()
-            if line.strip() and msg in line:
-                return line
+            if msg is not None:
+                msg = bytes(msg, "utf8")
+            if regex is not None:
+                regex = bytes(regex, "utf8")
+
+        if msg and regex:
+            raise ValueError("msg or regex should be provided, not both")
+        elif msg:
+            while not self.file_end(file_obj=file_obj):
+                line = file_obj.readline()
+                if line.strip() and msg in line:
+                    return line
+            raise ValueError("'{}' not found".format(msg))
+        elif regex:
+            test = re.compile(regex)
+            while not self.file_end(file_obj=file_obj):
+                line = file_obj.readline()
+                if test.match(line):
+                    return(line)
+            raise ValueError("'{}' not found".format(regex))
+        else:
+            raise ValueError("No msg or regex provided: nothing to match")
 
     def find_last(self, file_obj=None, msg=None):
         """
diff --git a/scripts/AbinsModules/GeneralLoadAbInitioTester.py b/scripts/AbinsModules/GeneralLoadAbInitioTester.py
index 5d6d26f129af3421196653572380bb3a77414039..08688c7f809dff764e6c5adb0124e17c5e4d6fc2 100644
--- a/scripts/AbinsModules/GeneralLoadAbInitioTester.py
+++ b/scripts/AbinsModules/GeneralLoadAbInitioTester.py
@@ -14,11 +14,16 @@ class GeneralLoadAbInitioTester(object):
 
     _loaders_extensions = {"LoadCASTEP": "phonon", "LoadCRYSTAL": "out", "LoadDMOL3": "outmol", "LoadGAUSSIAN": "log"}
 
-    # noinspection PyMethodMayBeStatic
-    def _prepare_data(self, filename=None):
-        """Reads reference values from ASCII file."""
+    @staticmethod
+    def _prepare_data(seedname):
+        """Reads reference values from ASCII files
 
-        with open(AbinsModules.AbinsTestHelpers.find_file(filename + "_data.txt")) as data_file:
+        :param seedname: Reference data will read from the file {seedname}_data.txt, except for the atomic displacements
+            which are read from files {seedname}_atomic_displacements_data_{I}.txt, where {I} are k-point indices.
+        :type seedname: str
+        """
+
+        with open(AbinsModules.AbinsTestHelpers.find_file(seedname + "_data.txt")) as data_file:
             correct_data = json.loads(data_file.read().replace("\n", " "))
 
         num_k = len(correct_data["datasets"]["k_points_data"]["weights"])
@@ -26,9 +31,9 @@ class GeneralLoadAbInitioTester(object):
         array = {}
         for k in range(num_k):
 
-            temp = np.loadtxt(
-                AbinsModules.AbinsTestHelpers.find_file(
-                    filename + "_atomic_displacements_data_%s.txt" % k)).view(complex).reshape(-1)
+            temp = np.loadtxt(AbinsModules.AbinsTestHelpers.find_file(
+                    "{seedname}_atomic_displacements_data_{k}.txt".format(seedname=seedname, k=k))
+                ).view(complex).reshape(-1)
             total_size = temp.size
             num_freq = int(total_size / (atoms * 3))
             array[str(k)] = temp.reshape(atoms, num_freq, 3)
@@ -123,13 +128,16 @@ class GeneralLoadAbInitioTester(object):
         data = self._read_ab_initio(loader=loader, filename=name, extension=extension)
 
         # get correct data
-        correct_data = self._prepare_data(filename=name)
+        correct_data = self._prepare_data(name)
 
         # check read data
         self._check_reader_data(correct_data=correct_data, data=data, filename=name, extension=extension)
 
         # check loaded data
-        self._check_loader_data(correct_data=correct_data, input_ab_initio_filename=name, extension=extension, loader=loader)
+        self._check_loader_data(correct_data=correct_data,
+                                input_ab_initio_filename=name,
+                                extension=extension,
+                                loader=loader)
 
     def _read_ab_initio(self, loader=None, filename=None, extension=None):
         """
@@ -146,15 +154,15 @@ class GeneralLoadAbInitioTester(object):
             read_filename = AbinsModules.AbinsTestHelpers.find_file(filename=filename + "." + extension.upper())
             ab_initio_reader = loader(input_ab_initio_filename=read_filename)
 
-        data = self._get_reader_data(ab_initio_reader=ab_initio_reader)
+        data = self._get_reader_data(ab_initio_reader)
 
         # test validData method
         self.assertEqual(True, ab_initio_reader._clerk._valid_hash())
 
         return data
 
-    # noinspection PyMethodMayBeStatic
-    def _get_reader_data(self, ab_initio_reader=None):
+    @staticmethod
+    def _get_reader_data(ab_initio_reader):
         """
         :param ab_initio_reader: object of type  GeneralAbInitioProgram
         :returns: read data
@@ -165,3 +173,46 @@ class GeneralLoadAbInitioTester(object):
                 }
         data["datasets"].update({"unit_cell": ab_initio_reader._clerk._data["unit_cell"]})
         return data
+
+    @classmethod
+    def save_ab_initio_test_data(cls, ab_initio_reader, seedname):
+        """
+        Write ab initio calculation data to JSON file for use in test cases
+
+        :param ab_initio_reader: Reader after import of external calculation
+        :type ab_initio_reader: AbinsModules.GeneralAbInitioProgram
+        :param filename: Seed for text files for JSON output. Data will be written to the file {seedname}_data.txt,
+            except for the atomic displacements which are written to files {seedname}_atomic_displacements_data_{I}.txt,
+            where {I} are k-point indices.
+        :type filename: str
+
+        """
+
+        data = cls._get_reader_data(ab_initio_reader)
+        # Unpack advanced parameters into a dictionary for ease of comparison later.
+        # It might be wise to remove this and store escaped strings for consistency,
+        # but for now we don't want to disturb the old test data so follow its format.
+        data["attributes"]["advanced_parameters"] = json.loads(data["attributes"]["advanced_parameters"])
+
+        displacements = data["datasets"]["k_points_data"].pop("atomic_displacements")
+        for i, eigenvector in displacements.items():
+            with open('{seedname}_atomic_displacements_data_{i}.txt'.format(seedname=seedname, i=i), 'wt') as f:
+                eigenvector.flatten().view(float).tofile(f, sep=' ')
+
+        with open('{seedname}_data.txt'.format(seedname=seedname), 'wt') as f:
+            json.dump(cls._arrays_to_lists(data), f, indent=4, sort_keys=True)
+
+    @classmethod
+    def _arrays_to_lists(cls, mydict):
+        """Recursively convert numpy arrays in a nested dict to lists (i.e. valid JSON)
+
+        Returns a processed *copy* of the input dictionary: in-place values will not be altered."""
+        clean_dict = {}
+        for key, value in mydict.items():
+            if isinstance(value, np.ndarray):
+                clean_dict[key] = value.tolist()
+            elif isinstance(value, dict):
+                clean_dict[key] = cls._arrays_to_lists(value)
+            else:
+                clean_dict[key] = value
+        return clean_dict
diff --git a/scripts/AbinsModules/LoadCRYSTAL.py b/scripts/AbinsModules/LoadCRYSTAL.py
index 2c05bd5ded8ff6a5a03a484ecf14bf418f92ddc7..f82e8668975d8c5afc5947dbba6475b628fd0a5d 100644
--- a/scripts/AbinsModules/LoadCRYSTAL.py
+++ b/scripts/AbinsModules/LoadCRYSTAL.py
@@ -153,7 +153,7 @@ class LoadCRYSTAL(AbinsModules.GeneralAbInitioProgram):
         """
         coord_lines = []
         self._parser.find_first(file_obj=file_obj,
-                                msg="ATOM          X(ANGSTROM)         Y(ANGSTROM)         Z(ANGSTROM)")
+                                regex=r".*\s+ATOM\s+X\(ANGSTROM\)\s+Y\(ANGSTROM\)\s+Z\(ANGSTROM\)\s*$")
 
         file_obj.readline()  # Line: *******************************************************************************
 
diff --git a/scripts/test/AbinsLoadCRYSTALTest.py b/scripts/test/AbinsLoadCRYSTALTest.py
index 8d794d91e8fb538c024ee43a75f41c313756bb4f..4a4968e658ab4733012b6595124f34fc2e348cb6 100644
--- a/scripts/test/AbinsLoadCRYSTALTest.py
+++ b/scripts/test/AbinsLoadCRYSTALTest.py
@@ -17,7 +17,7 @@ class AbinsLoadCRYSTALTest(unittest.TestCase, AbinsModules.GeneralLoadAbInitioTe
 
         #  *************************** USE CASES ********************************************
     # ===================================================================================
-    # | Use cases: Gamma point calculation for CRYSTAL                                    |
+    # | Use cases: Gamma point calculation for CRYSTAL                                  |
     # ===================================================================================
     _gamma_crystal = "crystalB3LYP_LoadCRYSTAL"
     _set_crystal = "crystal_set_key_LoadCRYSTAL"
@@ -28,7 +28,12 @@ class AbinsLoadCRYSTALTest(unittest.TestCase, AbinsModules.GeneralLoadAbInitioTe
     _molecule = "toluene_molecule_LoadCRYSTAL"
 
     # ===================================================================================
-    # | Use cases: Phonon dispersion calculation for CRYSTAL                                     |
+    # | Use case: Molecular calculation with CRYSTAL17                                  |
+    # ===================================================================================
+    _molecule17 = "toluene_molecule_LoadCRYSTAL17"
+
+    # ===================================================================================
+    # | Use cases: Phonon dispersion calculation for CRYSTAL                            |
     # ===================================================================================
     _phonon_dispersion_v1 = "mgo-GX_LoadCRYSTAL"
     _phonon_dispersion_v2 = "MgO-222-DISP_LoadCRYSTAL"
@@ -40,6 +45,9 @@ class AbinsLoadCRYSTALTest(unittest.TestCase, AbinsModules.GeneralLoadAbInitioTe
     def test_molecule(self):
         self.check(name=self._molecule, loader=AbinsModules.LoadCRYSTAL)
 
+    def test_molecule17(self):
+        self.check(name=self._molecule17, loader=AbinsModules.LoadCRYSTAL)
+
     def test_phonon_dispersion_crystal(self):
         self.check(name=self._phonon_dispersion_v1, loader=AbinsModules.LoadCRYSTAL)
         self.check(name=self._phonon_dispersion_v2, loader=AbinsModules.LoadCRYSTAL)