Read in selected results of the inv.ctr file

        Parameters
        ----------
        tomodir: string
            directory path to a tomodir

        Returns
        -------
        inv_ctr:    ?
            structure containing inv.ctr data

def _read_inv_ctr(self, tomodir):
        """Read in selected results of the inv.ctr file

        Parameters
        ----------
        tomodir: string
            directory path to a tomodir

        Returns
        -------
        inv_ctr:    ?
            structure containing inv.ctr data

        """
        invctr_file = tomodir + os.sep + 'inv' + os.sep + 'inv.ctr'
        if not os.path.isfile(invctr_file):
            print('inv.ctr not found: {0}'.format(invctr_file))
            print(os.getcwd())
            return 1

        # read header
        with open(invctr_file, 'r') as fid:
            lines = fid.readlines()

        # check for robust inversion
        is_robust_inversion = False
        nr_of_data_points = None
        for i, line in enumerate(lines):
            if line.startswith('***PARAMETERS***'):
                raw_value = lines[i + 7].strip()[0]
                if raw_value == 'T':
                    is_robust_inversion = True
            if line.startswith('# Data points'):
                nr_of_data_points = int(line[15:].strip())

        print('is robust', is_robust_inversion)

        # find section that contains the iteration data
        for i, line in enumerate(lines):
            if line.strip().startswith('ID it.'):
                break

        # TODO: check for robust iteration

        # we have three types of lines:
        # 1. first iteration line
        # 2. other main iteration lines
        # 3. update lines

        # prepare regular expressions for these three types, each in two
        # flavors: robust and non-robust

        """
! first iteration, robust
100 FORMAT (t1,a3,t5,i3,t11,g10.4,t69,g10.4,t81,g10.4,t93,i4,t105,g9.3)
! first iteration, non-robust
101 FORMAT (t1,a3,t5,i3,t11,g10.4,t69,g10.4,t81,g10.4,t93,i4)

! other iterations, robust
110 FORMAT (t1,a3,t5,i3,t11,g10.4,t23,g10.4,t34,g10.4,t46,g10.4,t58,&
i6,t69,g10.4,t81,g10.4,t93,i4,t105,g9.3,t117,f5.3)
! other iterations, non-robust
111 FORMAT (t1,a3,t5,i3,t11,g10.4,t23,g10.4,t34,g10.4,t46,g10.4,t58,&
i6,t69,g10.4,t81,g10.4,t93,i4,t105,f5.3)

! update iterations, non-robust
105 FORMAT (t1,a3,t5,i3,t11,g10.4,t23,g9.3,t34,g10.4,t46,g10.4,t58,&
i6,t105,f5.3)
! update iterations, robust
106 FORMAT (t1,a3,t5,i3,t11,g10.4,t23,g9.3,t34,g10.4,t46,g10.4,t58,&
i6,t105,g9.3,t117,f5.3)

        """

        # this identifies a float number, or a NaN value
        reg_float = ''.join((
            '((?:[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?)',
            '|',
            '(?:NaN))'
        ))

        reg_int = '(\d{1,3})'

        # (t1,a3,t5,i3,t11,g10.4,t69,g10.4,t81,g10.4,t93,i4)
        # first iteration line of non-robust inversion
        reg_it1_norob = ''.join((
            '([a-zA-Z]{1,3})',
            ' *' + reg_int,
            ' *' + reg_float,
            ' *' + reg_float,
            ' *' + reg_float,
            ' *' + reg_int,
        ))
        # first iteration line of robust inversion
        reg_it1_robust = ''.join((
            '([a-zA-Z]{1,3})',
            ' *(\d{1,3})',
            ' *' + reg_float,   # data RMS
            ' *' + reg_float,   # mag RMS
            ' *' + reg_float,   # pha RMS
            ' *' + reg_int,     # nr excluded data
            ' *' + reg_float,   # L1-ratio
        ))

        # second-to-last iterations, robust
        reg_it2plus_rob = ''.join((
            '([a-zA-Z]{1,3})',
            ' *(\d{1,3})',
            ' *' + reg_float,   # data RMS
            ' *' + reg_float,   # stepsize
            ' *' + reg_float,   # lambda
            ' *' + reg_float,   # roughness
            ' *' + reg_int,     # CG-steps
            ' *' + reg_float,   # mag RMS
            ' *' + reg_float,   # pha RMS
            ' *' + reg_int,     # nr excluded data
            ' *' + reg_float,   # l1-ratio
            ' *' + reg_float,   # steplength
        ))

        # second-to-last iterations, non-robustk
        # (t1,a3,t5,i3,t11,g10.4,t23,g10.4,t34,g10.4,t46,g10.4,t58,&
        # i6,t69,g10.4,t81,g10.4,t93,i4,t105,f5.3)
        reg_it2plus_norob = ''.join((
            '([a-zA-Z]{1,3})',
            ' *(\d{1,3})',
            ' *' + reg_float,   # data RMS
            ' *' + reg_float,   # stepsize
            ' *' + reg_float,   # lambda
            ' *' + reg_float,   # roughness
            ' *' + reg_int,     # CG-steps
            ' *' + reg_float,   # mag RMS
            ' *' + reg_float,   # pha RMS
            ' *' + reg_int,     # nr excluded data
            ' *' + reg_float,   # steplength
        ))

        # update robust
        reg_update_rob = ''.join((
            '([a-zA-Z]{1,3})',
            ' *(\d{1,3})',
            ' *' + reg_float,  # data RMS
            ' *' + reg_float,  # stepsize
            ' *' + reg_float,  # lambda
            ' *' + reg_float,  # roughness
            ' *' + reg_int,  # CG-steps
            ' *' + reg_float,  # l1ratio
        ))
        # update non-robust
        reg_update_norob = ''.join((
            '([a-zA-Z]{1,3})',
            ' *(\d{1,3})',
            ' *' + reg_float,  # data RMS
            ' *' + reg_float,  # stepsize
            ' *' + reg_float,  # lambda
            ' *' + reg_float,  # roughness
            ' *' + reg_int,  # CG-steps
            ' *' + reg_float,  # steplength
        ))

        # iteration counter
        current_iteration = 0
        iterations = []

        for line in lines[i:]:
            linec = line.strip()
            if linec.startswith('IT') or linec.startswith('PIT'):
                if linec[0:3].strip() == 'IT':
                    it_type = 'DC/IP'
                else:
                    it_type = 'FPI'

                values = None

                # main iterations
                if is_robust_inversion:
                    if current_iteration == 0:
                        # first iteration, robust
                        g = re.compile(reg_it1_robust).search(linec).groups()
                        keyfuncs = [
                            (None, None),
                            ('iteration', int),
                            ('dataRMS', float),
                            ('magRMS', float),
                            ('phaRMS', float),
                            ('nrdata', int),
                            ('l1ratio', float),
                        ]
                        values = {}
                        for value, (key, func) in zip(g, keyfuncs):
                            if key is not None:
                                values[key] = func(value)
                    else:
                        # second-to-last iterations, robust
                        g = re.compile(
                            reg_it2plus_rob
                        ).search(linec).groups()
                        keyfuncs = [
                            (None, None),
                            ('iteration', int),
                            ('dataRMS', float),
                            ('stepsize', float),
                            ('lambda', float),
                            ('roughness', float),
                            ('cgsteps', int),
                            ('magRMS', float),
                            ('phaRMS', float),
                            ('nrdata', int),
                            ('l1ratio', float),
                            ('steplength', float),
                        ]
                        values = {}
                        for value, (key, func) in zip(g, keyfuncs):
                            if key is not None:
                                values[key] = func(value)
                    values['type'] = 'main'
                    values['main_iteration'] = current_iteration
                    values['it_type'] = it_type
                    iterations.append(values)
                    current_iteration += 1
                else:
                    if current_iteration == 0:
                        # non-robust, first iteration
                        g = re.compile(reg_it1_norob).search(linec).groups()

                        keyfuncs = [
                            (None, None),
                            ('iteration', int),
                            ('dataRMS', float),
                            ('magRMS', float),
                            ('phaRMS', float),
                            ('nrdata', int)
                        ]
                        values = {}
                        for value, (key, func) in zip(g, keyfuncs):
                            if key is not None:
                                values[key] = func(value)
                    else:
                        g = re.compile(
                            reg_it2plus_norob
                        ).search(linec).groups()
                        keyfuncs = [
                            (None, None),
                            ('iteration', int),
                            ('dataRMS', float),
                            ('stepsize', float),
                            ('lambda', float),
                            ('roughness', float),
                            ('cgsteps', int),
                            ('magRMS', float),
                            ('phaRMS', float),
                            ('nrdata', int),
                            ('steplength', float),
                        ]
                        values = {}
                        for value, (key, func) in zip(g, keyfuncs):
                            if key is not None:
                                values[key] = func(value)
                    values['type'] = 'main'
                    values['it_type'] = it_type
                    values['main_iteration'] = current_iteration
                    iterations.append(values)
                    current_iteration += 1
            elif linec.startswith('UP'):
                # update iterations
                if is_robust_inversion:
                    # robust
                    g = re.compile(
                        reg_update_rob
                    ).search(linec).groups()
                    keyfuncs = [
                        (None, None),
                        ('iteration', int),
                        ('dataRMS', float),
                        ('stepsize', float),
                        ('lambda', float),
                        ('roughness', float),
                        ('cgsteps', int),
                        ('l1-ratio', float),
                    ]
                    values = {}
                    for value, (key, func) in zip(g, keyfuncs):
                        if key is not None:
                            values[key] = func(value)
                else:
                    g = re.compile(
                        reg_update_norob
                    ).search(linec).groups()
                    keyfuncs = [
                        (None, None),
                        ('iteration', int),
                        ('dataRMS', float),
                        ('stepsize', float),
                        ('lambda', float),
                        ('roughness', float),
                        ('cgsteps', int),
                        ('steplength', float),
                    ]
                    values = {}
                    for value, (key, func) in zip(g, keyfuncs):
                        if key is not None:
                            values[key] = func(value)
                values['type'] = 'update'
                values['it_type'] = it_type
                values['main_iteration'] = current_iteration
                iterations.append(values)

        df = pd.DataFrame(iterations)
        df = df.reindex_axis([
            'iteration',
            'main_iteration',
            'it_type',
            'type',
            'dataRMS',
            'magRMS',
            'phaRMS',
            'lambda',
            'roughness',
            'cgsteps',
            'nrdata',
            'steplength',
            'stepsize',
            'l1ratio',
        ], axis=1)

        df['nrdata'] = nr_of_data_points - df['nrdata']
        return df