Instruction:
Can you implement a function in Python 3 that
reads the info of a specific child type and parent type from a specific file.

Response:
def get_magic_info(self, child_type, parent_type=None, attr='er',
                       filename=None, sort_by_file_type=False):
        """
        Read er_*.txt or pmag_*.txt file.
        If no filename is provided, use er_* or pmag_* file in WD.
        If sort_by_file_type, use file header to determine child, parent types,
        instead of passing those in as arguments.
        Once file is open, parse information into dictionaries for each item.
        If the item does not yet exist, add it to the builder data object.
        Then add info to the item object as object.er_data or object.pmag_data.
        """
        parent = ''
        grandparent_type = None
        magic_name = 'er_' + child_type + '_name'
        expected_item_type = child_type
        if not filename:
            short_filename = attr + '_' + child_type + 's.txt'
            magic_file = os.path.join(self.WD, short_filename)
        else:
            short_filename = os.path.split(filename)[1]
            magic_file = filename
            attr = short_filename.split('_')[0]
        print('-I- Attempting to read {}'.format(magic_file))
        if not os.path.isfile(magic_file):
            print('-W- Could not find {}'.format(magic_file))
            return False
        # get the data from the appropriate .txt file

        data_dict, header, file_type = self.read_magic_file(magic_file, magic_name,
                                                            sort_by_file_type=sort_by_file_type)
        if not data_dict:
            print('-W- Could not read in file: {}.\n    Make sure it is a MagIC-format file'.format(magic_file))
            return False

        item_type = file_type.split('_')[1][:-1]
        # if a file was named wrong, use the type of data that is actually in that file
        if item_type != expected_item_type:
            print('-W- Expected data of type: {} but instead got: {}'.format(expected_item_type,
                                                                             item_type))
            print('-W- Using type: {}'.format(item_type))
            if item_type == 'age':
                self.get_age_info(filename)
                return 'age'
            child_type = item_type
            magic_name = 'er_' + child_type + '_name'
            ind = self.ancestry.index(child_type)
            parent_type = self.ancestry[ind+1]
            if item_type != 'location':
                grandparent_type = self.ancestry[ind+2]
            else:
                grandparent_type = ''
        if not grandparent_type:
            ind = self.ancestry.index(child_type)
            try:
                grandparent_type = self.ancestry[ind+2]
            except IndexError:
                grandparent_type = None
        child_list, child_class, child_constructor = self.data_lists[child_type]

        if parent_type:
            parent_list, parent_class, parent_constructor = self.data_lists[parent_type]
        else:
            parent_list, parent_name = None, None
        for child_name in data_dict:
            # if there is a possible parent, try to find parent object in the data model
            if parent_type:
                parent_name = data_dict[child_name].get('er_' + parent_type + '_name', '')
                parent = self.find_by_name(parent_name, parent_list)
                if parent:
                    remove_dict_headers(parent.er_data)
                    remove_dict_headers(parent.pmag_data)
            # if there should be a parent
            # (meaning there is a name for it and the child object should have a parent)
            # but none exists in the data model, go ahead and create that parent object.
            if parent_name and parent_type and not parent:
                # try to get grandparent
                grandparent = None
                grandparent_name = None
                if grandparent_type:
                    grandparent_list, grandparent_class, grandparent_constructor = self.data_lists[grandparent_type]
                    grandparent_name = data_dict[child_name]['er_' + grandparent_type + '_name']
                    grandparent = self.find_by_name(grandparent_name, grandparent_list)
                    if grandparent_name and not grandparent:
                        grandparent = grandparent_constructor(grandparent_name, None)
                parent = parent_constructor(parent_name, grandparent_name)
            # otherwise there is no parent and none can be created, so use an empty string
            elif not parent:
                parent_name = None
                parent = ''
            child = self.find_by_name(child_name, child_list)
            # if the child object does not exist yet in the data model
            if not child:
                child = child_constructor(child_name, parent_name)
            else:
                # bind parent to child and child to parent
                if parent:
                    child.set_parent(parent)
                if parent and (child not in parent.children):
                    parent.add_child(child)

            # add in the appropriate data dictionary to the child object
            if attr == 'er':
                self.update_methods[child_type](child_name, child_name, parent_name,
                                                new_er_data=data_dict[child_name])
            else:
                self.update_methods[child_type](child_name, child_name, parent_name,
                                                new_pmag_data=data_dict[child_name])
            # old way
            #child.__setattr__(attr + '_data', data_dict[child_name])
            remove_dict_headers(child.er_data)
            remove_dict_headers(child.pmag_data)
            #
        return child_type


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_age_info(self, filename=None):
        # use filename if provided, otherwise find er_ages.txt in WD
        if not filename:
            short_filename = 'er_ages.txt'
            magic_file = os.path.join(self.WD, short_filename)
        else:
            magic_file = filename
        if not os.path.isfile(magic_file):
            print('-W- Could not find {}'.format(magic_file))
            return False

        data_dict, header, file_type = self.read_magic_file(magic_file, 'by_line_number')
        # if provided file is not an age_file,
        # try to read it in as whatever type of file it actually is
        if file_type != 'er_ages':
            item_type = file_type.split('_')[1][:-1]
            self.get_magic_info(item_type, filename=filename, sort_by_file_type=True)
            return file_type

        # if it is an age file,
        # determine level for each age and assign it to the appropriate pmag object
        for item_dict in list(data_dict.values()):
            item_type = None
            for dtype in ['specimen', 'sample', 'site', 'location']:
                header_name = 'er_' + dtype + '_name'
                if header_name in list(item_dict.keys()):
                    if item_dict[header_name]:
                        item_type = dtype
                        item_name = item_dict[header_name].strip()
                        break
            if not item_type:
                print('-W- You must provide a name for your age')
                print('    These data:\n{}\n    will not be imported'.format(item_dict))
                continue
            items_list = self.data_lists[item_type][0]
            item = self.find_by_name(item_name, items_list)
            if not item:
                ## the following code creates any item in er_ages that does not exist already
                ## however, we may not WANT that behavior
                print("""-I- A {} named {} in your age file was not found in the data object:
    Now initializing {} {}""".format(item_type, item_name, item_type, item_name))
                ind = self.ancestry.index(item_type)
                parent_type = self.ancestry[ind+1]
                parent_header, parent_constructor = None, None
                if parent_type:
                    parent_list, parent_class, parent_constructor = self.data_lists[parent_type]
                    parent_header = 'er_' + parent_type + '_name'
                parent_name = item_dict.get(parent_header, '')
                parent = self.find_by_name(parent_name, parent_list)
                # if the parent item doesn't exist, and should, create it
                if parent_name and not parent:
                    print("""-I- A {} named {} in your age file was not found in the data object:
    Now initializing {} {}""".format(parent_type, parent_name, parent_type, parent_name))
                    parent = parent_constructor(parent_name, None)
                item_constructor = self.data_lists[item_type][2]
                if not parent:
                    parent_name = None
                item = item_constructor(item_name, parent_name)
            # add the age data to the object
            item.age_data = remove_dict_headers(item_dict)
        # note that data is available to write
        self.write_ages = True
        return file_type

Response: Read er_ages. txt file and return the age information.


Instruction:
Implement a Python 3 function for
reading pmag_results. txt file and parse it into dictionaries and add it to the results_data attribute.

Response:
def get_results_info(self, filename=None):
        """
        Read pmag_results.txt file.
        Parse information into dictionaries for each item.
        Then add it to the item object as object.results_data.
        """
        if not filename:
            short_filename = "pmag_results.txt"
            magic_file = os.path.join(self.WD, short_filename)
        else:
            magic_file = filename
        if not os.path.isfile(magic_file):
            print('-W- Could not find {} in your working directory {}'.format(short_filename, self.WD))
            return False
        # get the data from the pmag_results.txt file
        data_dict = self.read_magic_file(magic_file, 'by_line_number')[0]

        def make_items_list(string, search_items_list):
            names = string.split(':')
            items = []
            for name in names:
                name = name.strip(' ')
                item = self.find_by_name(name, search_items_list)
                if item:
                    items.append(item)
            return items

        for num, result in list(data_dict.items()):
            name, specimens, samples, sites, locations = None, None, None, None, None
            for key, value in list(result.items()):
                #print key, ':', value
                if key == 'er_specimen_names':
                    specimens = make_items_list(value, self.specimens)
                if key == 'er_sample_names':
                    samples = make_items_list(value, self.samples)
                if key == 'er_site_names':
                    sites = make_items_list(value, self.sites)
                if key == 'er_location_names':
                    locations = make_items_list(value, self.locations)
                if key == 'pmag_result_name':
                    name = value
            for header_name in ['er_specimen_names', 'er_site_names',
                                'er_sample_names', 'er_location_names']:
                if header_name in list(result.keys()):
                    result.pop(header_name)
            if not name:
                name = num
            result_item = self.find_by_name(name, self.results)
            if not result_item:
                result_item = Result(name, specimens, samples, sites, locations, result, self.data_model)
            else:
                print('-W- Two or more results with name: {} found in your result file.\n    Taking only the first.'.format(name))
            if result_item and result_item not in self.results:
                self.results.append(result_item)


Instruction:
Write a Python 3 function for
reading a magic - formatted tab - delimited file and return a dictionary of dictionaries with keys that are the names of the specimen classes and the values that are the values of the specimen types.

Response:
def read_magic_file(self, path, sort_by_this_name, sort_by_file_type=False):
        """
        read a magic-formatted tab-delimited file.
        return a dictionary of dictionaries, with this format:
        {'Z35.5a': {'specimen_weight': '1.000e-03', 'er_citation_names': 'This study', 'specimen_volume': '', 'er_location_name': '', 'er_site_name': 'Z35.', 'er_sample_name': 'Z35.5', 'specimen_class': '', 'er_specimen_name': 'Z35.5a', 'specimen_lithology': '', 'specimen_type': ''}, ....}
        """
        DATA = {}
        with open(path, 'r') as fin:
            lines = list(fin.readlines())
        first_line = lines[0]
        if not first_line:
            return False, None, 'empty_file'
        if first_line[0] == "s" or first_line[1] == "s":
            delim = ' '
        elif first_line[0] == "t" or first_line[1] == "t":
            delim = '\t'
        else:
            print('-W- error reading ', path)
            return False, None, 'bad_file'

        file_type = first_line.strip('\n').split(delim)[1]
        if sort_by_file_type:
            item_type = file_type.split('_')[1][:-1]
            if item_type == 'age':
                sort_by_this_name = "by_line_number"
            else:
                sort_by_this_name = 'er_' + item_type + '_name'
        line = lines[1]
        header = line.strip('\n').split(delim)
        counter = 0
        for line in lines[2:]:
            tmp_data = {}
            tmp_line = line.strip('\n').split(delim)
            for i in range(len(header)):
                if i < len(tmp_line):
                    tmp_data[header[i]] = tmp_line[i].strip()
                else:
                    tmp_data[header[i]] = ""
            if sort_by_this_name == "by_line_number":
                DATA[counter] = tmp_data
                counter += 1
            else:
                if tmp_data[sort_by_this_name] != "":
                    DATA[tmp_data[sort_by_this_name]] = tmp_data
        return DATA, header, file_type


Instruction:
How would you explain what the following Python 3 function does
def write_files(self):
        warnings = self.validate_data()

        print('-I- Writing all saved data to files')
        if self.measurements:
            self.write_measurements_file()
        for dtype in ['specimen', 'sample', 'site']:
            if self.data_lists[dtype][0]:
                do_pmag = dtype in self.incl_pmag_data
                self.write_magic_file(dtype, do_er=True, do_pmag=do_pmag)
                if not do_pmag:
                    pmag_file = os.path.join(self.WD, 'pmag_' + dtype + 's.txt')
                    if os.path.isfile(pmag_file):
                        os.remove(pmag_file)

        if self.locations:
            self.write_magic_file('location', do_er=True, do_pmag=False)

        self.write_age_file()

        if self.results:
            self.write_result_file()

        if warnings:
            print('-W- ' + str(warnings))
            return False, warnings

        return True, None

Response: write all data into er_* and pmag_* files as appropriate


Instruction:
Create a Python 3 function for
writing er_ages. txt based on updated ErMagicBuilder data object

Response:
def write_age_file(self):
        """
        Write er_ages.txt based on updated ErMagicBuilder data object
        """
        if not self.write_ages:
            print('-I- No age data available to write')
            return
        first_headers = self.first_age_headers
        actual_headers = sorted(self.headers['age']['er'][0])
        for header in first_headers:
            if header in actual_headers:
                actual_headers.remove(header)
        add_headers = ['er_specimen_name', 'er_sample_name', 'er_site_name', 'er_location_name']
        actual_headers[:0] = first_headers
        full_headers = add_headers[:]
        full_headers.extend(actual_headers)

        header_string = '\t'.join(full_headers)
        ages = []
        for dtype in ['specimen', 'sample', 'site', 'location']:
            ages_list = sorted(self.data_lists[dtype][0], key=lambda item: item.name)
            ages.extend(ages_list)

        age_strings = []
        for age in ages:
            ind = self.ancestry.index(age.dtype)
            ancestors = ['' for num in range(len(self.ancestry) - (ind+2))]
            data_found = False
            string = ''
            if age.dtype == 'specimen':
                string += age.name + '\t'
            elif age.dtype == 'sample':
                string += '\t' + age.name + '\t'
            elif age.dtype == 'site':
                string += '\t\t' + age.name + '\t'
            elif age.dtype == 'location':
                string += '\t\t\t' + age.name + '\t'
            parent = age.get_parent()
            grandparent = None
            if parent:
                ancestors[0] = parent.name
                grandparent = parent.get_parent()
                if grandparent:
                    ancestors[1] = grandparent.name
                    greatgrandparent = grandparent.get_parent()
                    if greatgrandparent:
                        ancestors[2] = greatgrandparent.name
            for ancestor in ancestors:
                string += ancestor + '\t'
            for key in actual_headers:
                try:
                    add_string = age.age_data[key]
                except KeyError:
                    add_string = ''
                    age.age_data[key] = ''
                if add_string and not key == 'er_citation_names':
                    data_found = True
                if key == 'er_citation_names' and not add_string.strip('\t'):
                    add_string = 'This study'
                string += add_string + '\t'
            # prevent extra '' at the end of age string
            if string.endswith('\t'):
                string = string[:-1]
            # only write ages to file if there is data provided
            if data_found:
                age_strings.append(string)
        outfile = open(os.path.join(self.WD, 'er_ages.txt'), 'w')
        outfile.write('tab\ter_ages\n')
        outfile.write(header_string + '\n')
        if not age_strings:
            outfile.close()
            os.remove(os.path.join(self.WD, 'er_ages.txt'))
            return False
        for string in age_strings:
            outfile.write(string + '\n')
        outfile.close()
        return outfile


Instruction:
Make a summary of the following Python 3 code
def validate_data(self):
        warnings = {}
        spec_warnings, samp_warnings, site_warnings, loc_warnings = {}, {}, {}, {}
        if self.specimens:
            spec_warnings = self.validate_items(self.specimens, 'specimen')
        if self.samples:
            samp_warnings = self.validate_items(self.samples, 'sample')
        if self.sites:
            site_warnings = self.validate_items(self.sites, 'site')
        if self.locations:
            loc_warnings = self.validate_items(self.locations, 'location')
        return spec_warnings, samp_warnings, site_warnings, loc_warnings

Response: Validate specimen sample site and location data.


Instruction:
Implement a function in Python 3 to
validate a list of items and return a dictionary of errors.

Response:
def validate_items(self, item_list, item_type):
        """
        Go through a list Pmag_objects and check for:
        parent errors,
        children errors,
        type errors.
        Return a dictionary of exceptions in this format:
        {sample1: {'parent': [warning1, warning2, warning3], 'child': [warning1, warning2]},
         sample2: {'child': [warning1], 'type': [warning1, warning2]},
          ...}

        """
        def append_or_create_dict_item(warning_type, dictionary, key, value):
            """
            Add to dictionary with this format:
            {key1: {warning_type1: [value1, value2], warning_type2: [value1]},
            ...}
            """
            if not value:
                return
            try:
                name = key.name
            except AttributeError:
                name = key
            if not name in dictionary:
                dictionary[name] = {}
            if not warning_type in dictionary[name]:
                dictionary[name][warning_type] = []
            for v in value:
                dictionary[name][warning_type].append(v)

        def check_item_type(item, item_type):#, warnings=None):
            """
            Make sure that item has appropriate type, and is in the data object.
            """
            warnings = []
            item_list, item_class, item_constructor = self.data_lists[item_type]
            if not isinstance(item, item_class):
                warnings.append(PmagException('wrong type'))
            if item not in item_list:
                warnings.append(PmagException('not in data object'))
            return warnings

        def check_item_for_parent(item, item_type, parent_type):
            """
            Make sure that item has a parent of the correct type
            """
            if not parent_type:
                return []
            if not isinstance(item, Pmag_object):
                return []
            warnings = []
            parent = item.get_parent()
            parent_list, parent_class, parent_constructor = self.data_lists[parent_type]
            if not parent or not parent.name:
                warnings.append(PmagException('missing parent'))
                return warnings
            if not isinstance(parent, parent_class):
                warnings.append(PmagException('invalid parent type', parent))
            if not parent in parent_list:
                warnings.append(PmagException('parent not in data object', parent))
            return warnings

        def check_item_for_children(item, child_type):
            """
            Make sure that any children are of the correct type,
            and are in the data object
            """
            if not child_type:
                return []
            warnings = []
            children = item.children
            child_list, child_class, child_constructor = self.data_lists[child_type]
            for child in children:
                if not isinstance(child, child_class):
                    warnings.append(PmagException('child has wrong type', child))
                if not child in child_list:
                    warnings.append(PmagException('child not in data object', child))
            return warnings

        warnings = {}
        type_ind = self.ancestry.index(item_type)
        parent_type = self.ancestry[type_ind+1]
        child_type = self.ancestry[type_ind-1]
        for item in item_list:
            #warnings[item] = []
            type_warnings = check_item_type(item, item_type)
            append_or_create_dict_item('type', warnings, item, type_warnings)
            parent_warnings = check_item_for_parent(item, item_type, parent_type)
            append_or_create_dict_item('parent', warnings, item, parent_warnings)
            child_warnings = check_item_for_children(item, child_type)
            append_or_create_dict_item('children', warnings, item, child_warnings)
        return warnings


Instruction:
Can you tell what is the following Python 3 function doing
def get_min_max_lat_lon(self, locations):
        d = {}
        for location in locations:
            sites = location.sites
            max_lat, min_lat = '', ''
            max_lon, min_lon = '', ''
            if not any(sites):
                d[location.name] = {'location_begin_lat': min_lat, 'location_begin_lon': min_lon,
                                    'location_end_lat': max_lat, 'location_end_lon': max_lon}
                #return d
                continue
            lats, lons = [], []
            # try to fill in min/max latitudes/longitudes from sites
            for site in sites:
                if site.er_data['site_lon']:
                    lons.append(site.er_data['site_lon'])
                if site.er_data['site_lat']:
                    lats.append(site.er_data['site_lat'])
            if lats:
                lats = [float(lat) for lat in lats]
                max_lat = max(lats)
                min_lat = min(lats)
            if lons:
                lons = [float(lon) for lon in lons]
                max_lon = max(lons)
                min_lon = min(lons)
            d[location.name] = {'location_begin_lat': min_lat, 'location_begin_lon': min_lon,
                                'location_end_lat': max_lat, 'location_end_lon': max_lon}
        return d

Response: Take a list of locations and return a dictionary with the keys location_begin_lat location_begin_lon location_end_lat and location_end_lon.


Instruction:
Make a summary of the following Python 3 code
def set_parent(self, new_samp):
        self.sample = new_samp
        if new_samp:
            if not isinstance(new_samp, Sample):
                raise Exception
        self.propagate_data()
        return new_samp

Response: Set self. sample as either an empty string or a new Sample.


Instruction:
Can you generate the documentation for the following Python 3 function
def set_parent(self, new_site):
        if new_site:
            if not isinstance(new_site, Site):
                raise Exception
        self.site = new_site
        self.propagate_data()
        return new_site

Response: Set self. site as either an empty string or a new Site.


Instruction:
Write a Python 3 script to
change the name location er_data and pmag_data of a specific site.

Response:
def change_site(self, new_name, new_location=None, new_er_data=None,
                    new_pmag_data=None, replace_data=False):
        """
        Update a site's name, location, er_data, and pmag_data.
        By default, new data will be added in to pre-existing data, overwriting existing values.
        If replace_data is True, the new data dictionary will simply take the place of the existing dict.
        """
        self.name = new_name
        if new_location:
            self.location = new_location
        self.update_data(new_er_data, new_pmag_data, replace_data)


Instruction:
Can you write a function in Python 3 where it
names thellier_magic.py DESCRIPTION plots Thellier-Thellier, allowing interactive setting of bounds and customizing of selection criteria. Saves and reads interpretations from a pmag_specimen formatted table, default: thellier_specimens.txt SYNTAX thellier_magic.py [command line options] OPTIONS -h prints help message and quits -f MEAS, set magic_measurements input file -fsp PRIOR, set pmag_specimen prior interpretations file -fan ANIS, set rmag_anisotropy file for doing the anisotropy corrections -fcr CRIT, set criteria file for grading. -fmt [svg,png,jpg], format for images - default is svg -sav, saves plots with out review (default format) -spc SPEC, plots single specimen SPEC, saves plot with specified format with optional -b bounds adn quits -b BEG END: sets bounds for calculation BEG: starting step for slope calculation END: ending step for slope calculation -z use only z component difference for pTRM calculation DEFAULTS MEAS: magic_measurements.txt REDO: thellier_redo CRIT: NONE PRIOR: NONE OUTPUT figures: ALL: numbers refer to temperature steps in command line window 1) Arai plot: closed circles are zero-field first/infield open circles are infield first/zero-field triangles are pTRM checks squares are pTRM tail checks VDS is vector difference sum diamonds are bounds for interpretation 2) Zijderveld plot: closed (open) symbols are X-Y (X-Z) planes X rotated to NRM direction 3) (De/Re)Magnetization diagram: circles are NRM remaining squares are pTRM gained 4) equal area projections: green triangles are pTRM gained direction red (purple) circles are lower(upper) hemisphere of ZI step directions blue (cyan) squares are lower(upper) hemisphere IZ step directions 5) Optional: TRM acquisition 6) Optional: TDS normalization command line window: list is: temperature step numbers, temperatures (C), Dec, Inc, Int (units of magic_measuements) list of possible commands: type letter followed by return to select option saving of plots creates .svg format files with specimen_name, plot type as name

Response:
def main():
    """
    NAME
        thellier_magic.py

    DESCRIPTION
        plots Thellier-Thellier, allowing interactive setting of bounds
        and customizing of selection criteria.  Saves and reads interpretations
        from a pmag_specimen formatted table, default: thellier_specimens.txt

    SYNTAX
        thellier_magic.py [command line options]

    OPTIONS
        -h prints help message and quits
        -f MEAS, set magic_measurements input file
        -fsp PRIOR, set pmag_specimen prior interpretations file
        -fan ANIS, set rmag_anisotropy file for doing the anisotropy corrections
        -fcr CRIT, set criteria file for grading.
        -fmt [svg,png,jpg], format for images - default is svg
        -sav,  saves plots with out review (default format)
        -spc SPEC, plots single specimen SPEC, saves plot with specified format
            with optional -b bounds adn quits
        -b BEG END: sets  bounds for calculation
           BEG: starting step for slope calculation
           END: ending step for slope calculation
        -z use only z component difference for pTRM calculation

    DEFAULTS
        MEAS: magic_measurements.txt
        REDO: thellier_redo
        CRIT: NONE
        PRIOR: NONE

    OUTPUT
        figures:
            ALL:  numbers refer to temperature steps in command line window
            1) Arai plot:  closed circles are zero-field first/infield
                           open circles are infield first/zero-field
                           triangles are pTRM checks
                           squares are pTRM tail checks
                           VDS is vector difference sum
                           diamonds are bounds for interpretation
            2) Zijderveld plot:  closed (open) symbols are X-Y (X-Z) planes
                                 X rotated to NRM direction
            3) (De/Re)Magnetization diagram:
                           circles are NRM remaining
                           squares are pTRM gained
            4) equal area projections:
               green triangles are pTRM gained direction
                           red (purple) circles are lower(upper) hemisphere of ZI step directions
                           blue (cyan) squares are lower(upper) hemisphere IZ step directions
            5) Optional:  TRM acquisition
            6) Optional: TDS normalization
        command line window:
            list is: temperature step numbers, temperatures (C), Dec, Inc, Int (units of magic_measuements)
                     list of possible commands: type letter followed by return to select option
                     saving of plots creates .svg format files with specimen_name, plot type as name
    """
#
#   initializations
#
    meas_file, critout, inspec = "magic_measurements.txt", "", "thellier_specimens.txt"
    first = 1
    inlt = 0
    version_num = pmag.get_version()
    TDinit, Tinit, field, first_save = 0, 0, -1, 1
    user, comment, AniSpec, locname = "", '', "", ""
    ans, specimen, recnum, start, end = 0, 0, 0, 0, 0
    plots, pmag_out, samp_file, style = 0, "", "", "svg"
    verbose = pmagplotlib.verbose
    fmt = '.'+style
#
# default acceptance criteria
#
    accept = pmag.default_criteria(0)[0]  # set the default criteria
#
# parse command line options
#
    Zdiff, anis = 0, 0
    spc, BEG, END = "", "", ""
    if '-h' in sys.argv:
        print(main.__doc__)
        sys.exit()
    if '-f' in sys.argv:
        ind = sys.argv.index('-f')
        meas_file = sys.argv[ind+1]
    if '-fsp' in sys.argv:
        ind = sys.argv.index('-fsp')
        inspec = sys.argv[ind+1]
    if '-fan' in sys.argv:
        ind = sys.argv.index('-fan')
        anisfile = sys.argv[ind+1]
        anis = 1
        anis_data, file_type = pmag.magic_read(anisfile)
        if verbose:
            print("Anisotropy data read in from ", anisfile)
    if '-fmt' in sys.argv:
        ind = sys.argv.index('-fmt')
        fmt = '.'+sys.argv[ind+1]
    if '-dpi' in sys.argv:
        ind = sys.argv.index('-dpi')
        dpi = '.'+sys.argv[ind+1]
    else:
        dpi = 100
    if '-sav' in sys.argv:
        plots = 1
        verbose = 0
    if '-z' in sys.argv:
        Zdiff = 1
    if '-spc' in sys.argv:
        ind = sys.argv.index('-spc')
        spc = sys.argv[ind+1]
        if '-b' in sys.argv:
            ind = sys.argv.index('-b')
            BEG = int(sys.argv[ind+1])
            END = int(sys.argv[ind+2])
    if '-fcr' in sys.argv:
        ind = sys.argv.index('-fcr')
        critout = sys.argv[ind+1]
        crit_data, file_type = pmag.magic_read(critout)
        if file_type != 'pmag_criteria':
            if verbose:
                print('bad pmag_criteria file, using no acceptance criteria')
            accept = pmag.default_criteria(1)[0]
        else:
            if verbose:
                print("Acceptance criteria read in from ", critout)
            accept = {'pmag_criteria_code': 'ACCEPTANCE',
                      'er_citation_names': 'This study'}
            for critrec in crit_data:
                if 'sample_int_sigma_uT' in critrec.keys():  # accommodate Shaar's new criterion
                    critrec['sample_int_sigma'] = '%10.3e' % (
                        eval(critrec['sample_int_sigma_uT'])*1e-6)
                for key in critrec.keys():
                    if key not in accept.keys() and critrec[key] != '':
                        accept[key] = critrec[key]
    try:
        open(inspec, 'rU')
        PriorRecs, file_type = pmag.magic_read(inspec)
        if file_type != 'pmag_specimens':
            print(file_type)
            print(file_type, inspec, " is not a valid pmag_specimens file ")
            sys.exit()
        for rec in PriorRecs:
            if 'magic_software_packages' not in rec.keys():
                rec['magic_software_packages'] = ""
    except IOError:
        PriorRecs = []
        if verbose:
            print("starting new specimen interpretation file: ", inspec)
    meas_data, file_type = pmag.magic_read(meas_file)
    if file_type != 'magic_measurements':
        print(file_type)
        print(file_type, "This is not a valid magic_measurements file ")
        sys.exit()
    backup = 0
    # define figure numbers for arai, zijderveld and
    #   de-,re-magization diagrams
    AZD = {}
    AZD['deremag'], AZD['zijd'], AZD['arai'], AZD['eqarea'] = 1, 2, 3, 4
    pmagplotlib.plot_init(AZD['arai'], 5, 5)
    pmagplotlib.plot_init(AZD['zijd'], 5, 5)
    pmagplotlib.plot_init(AZD['deremag'], 5, 5)
    pmagplotlib.plot_init(AZD['eqarea'], 5, 5)
    #
    #
    #
    # get list of unique specimen names
    #
    CurrRec = []
    sids = pmag.get_specs(meas_data)
    # get plots for specimen s - default is just to step through arai diagrams
    #
    if spc != "":
        specimen = sids.index(spc)
    while specimen < len(sids):
        methcodes = []

        if verbose:
            print(sids[specimen], specimen+1, 'of ', len(sids))
        MeasRecs = []
        s = sids[specimen]
        datablock, trmblock, tdsrecs = [], [], []
        PmagSpecRec = {}
        if first == 0:
            for key in keys:
                # make sure all new records have same set of keys
                PmagSpecRec[key] = ""
        PmagSpecRec["er_analyst_mail_names"] = user
        PmagSpecRec["specimen_correction"] = 'u'
    #
    # find the data from the meas_data file for this specimen
    #
        for rec in meas_data:
            if rec["er_specimen_name"] == s:
                MeasRecs.append(rec)
                if "magic_method_codes" not in rec.keys():
                    rec["magic_method_codes"] = ""
                methods = rec["magic_method_codes"].split(":")
                meths = []
                for meth in methods:
                    meths.append(meth.strip())  # take off annoying spaces
                methods = ""
                for meth in meths:
                    if meth.strip() not in methcodes and "LP-" in meth:
                        methcodes.append(meth.strip())
                    methods = methods+meth+":"
                methods = methods[:-1]
                rec["magic_method_codes"] = methods
                if "LP-PI-TRM" in meths:
                    datablock.append(rec)
                if "LP-TRM" in meths:
                    trmblock.append(rec)
                if "LP-TRM-TD" in meths:
                    tdsrecs.append(rec)
        if len(trmblock) > 2 and inspec != "":
            if Tinit == 0:
                Tinit = 1
                AZD['TRM'] = 5
                pmagplotlib.plot_init(AZD['TRM'], 5, 5)
        elif Tinit == 1:  # clear the TRM figure if not needed
            pmagplotlib.clearFIG(AZD['TRM'])
        if len(tdsrecs) > 2:
            if TDinit == 0:
                TDinit = 1
                AZD['TDS'] = 6
                pmagplotlib.plot_init(AZD['TDS'], 5, 5)
        elif TDinit == 1:  # clear the TDS figure if not needed
            pmagplotlib.clearFIG(AZD['TDS'])
        if len(datablock) < 4:
            if backup == 0:
                specimen += 1
                if verbose:
                    print('skipping specimen - moving forward ', s)
            else:
                specimen -= 1
                if verbose:
                    print('skipping specimen - moving backward ', s)
    #
    #  collect info for the PmagSpecRec dictionary
    #
        else:
            rec = datablock[0]
            PmagSpecRec["er_citation_names"] = "This study"
            PmagSpecRec["er_specimen_name"] = s
            PmagSpecRec["er_sample_name"] = rec["er_sample_name"]
            PmagSpecRec["er_site_name"] = rec["er_site_name"]
            PmagSpecRec["er_location_name"] = rec["er_location_name"]
            locname = rec['er_location_name'].replace('/', '-')
            if "er_expedition_name" in rec.keys():
                PmagSpecRec["er_expedition_name"] = rec["er_expedition_name"]
            if "magic_instrument_codes" not in rec.keys():
                rec["magic_instrument_codes"] = ""
            PmagSpecRec["magic_instrument_codes"] = rec["magic_instrument_codes"]
            PmagSpecRec["measurement_step_unit"] = "K"
            if "magic_experiment_name" not in rec.keys():
                rec["magic_experiment_name"] = ""
            else:
                PmagSpecRec["magic_experiment_names"] = rec["magic_experiment_name"]

            meths = rec["magic_method_codes"].split()
        # sort data into types
            araiblock, field = pmag.sortarai(datablock, s, Zdiff)
            first_Z = araiblock[0]
            GammaChecks = araiblock[5]
            if len(first_Z) < 3:
                if backup == 0:
                    specimen += 1
                    if verbose:
                        print('skipping specimen - moving forward ', s)
                else:
                    specimen -= 1
                    if verbose:
                        print('skipping specimen - moving backward ', s)
            else:
                backup = 0
                zijdblock, units = pmag.find_dmag_rec(s, meas_data)
                recnum = 0
                if verbose:
                    print("index step Dec   Inc  Int       Gamma")
                    for plotrec in zijdblock:
                        if GammaChecks != "":
                            gamma = ""
                            for g in GammaChecks:
                                if g[0] == plotrec[0]-273:
                                    gamma = g[1]
                                    break
                        if gamma != "":
                            print('%i     %i %7.1f %7.1f %8.3e %7.1f' % (
                                recnum, plotrec[0]-273, plotrec[1], plotrec[2], plotrec[3], gamma))
                        else:
                            print('%i     %i %7.1f %7.1f %8.3e ' % (
                                recnum, plotrec[0]-273, plotrec[1], plotrec[2], plotrec[3]))
                        recnum += 1
                pmagplotlib.plot_arai_zij(AZD, araiblock, zijdblock, s, units[0])
                if verbose:
                    pmagplotlib.draw_figs(AZD)
                if len(tdsrecs) > 2:  # a TDS experiment
                    tdsblock = []  # make a list for the TDS  data
                    Mkeys = ['measurement_magnitude', 'measurement_magn_moment',
                             'measurement_magn_volume', 'measuruement_magn_mass']
                    mkey, k = "", 0
                    # find which type of intensity
                    while mkey == "" and k < len(Mkeys)-1:
                        key = Mkeys[k]
                        if key in tdsrecs[0].keys() and tdsrecs[0][key] != "":
                            mkey = key
                        k += 1
                    if mkey == "":
                        break  # get outta here
                    Tnorm = ""
                    for tdrec in tdsrecs:
                        meths = tdrec['magic_method_codes'].split(":")
                        for meth in meths:
                            # strip off potential nasty spaces
                            meth.replace(" ", "")
                        if 'LT-T-I' in meths and Tnorm == "":  # found first total TRM
                            # normalize by total TRM
                            Tnorm = float(tdrec[mkey])
                            # put in the zero step
                            tdsblock.append([273, zijdblock[0][3]/Tnorm, 1.])
                        # found a LP-TRM-TD demag step, now need complementary LT-T-Z from zijdblock
                        if 'LT-T-Z' in meths and Tnorm != "":
                            step = float(tdrec['treatment_temp'])
                            Tint = ""
                            if mkey != "":
                                Tint = float(tdrec[mkey])
                            if Tint != "":
                                for zrec in zijdblock:
                                    if zrec[0] == step:  # found matching
                                        tdsblock.append(
                                            [step, zrec[3]/Tnorm, Tint/Tnorm])
                                        break
                    if len(tdsblock) > 2:
                        pmagplotlib.plot_tds(
                            AZD['TDS'], tdsblock, s+':LP-PI-TDS:')
                        if verbose:
                            pmagplotlib(draw_figs(AZD))
                    else:
                        print("Something wrong here")
                if anis == 1:   # look up anisotropy data for this specimen
                    AniSpec = ""
                    for aspec in anis_data:
                        if aspec["er_specimen_name"] == PmagSpecRec["er_specimen_name"]:
                            AniSpec = aspec
                            if verbose:
                                print('Found anisotropy record...')
                            break
                if inspec != "":
                    if verbose:
                        print('Looking up saved interpretation....')
                    found = 0
                    for k in range(len(PriorRecs)):
                        try:
                            if PriorRecs[k]["er_specimen_name"] == s:
                                found = 1
                                CurrRec.append(PriorRecs[k])
                                for j in range(len(zijdblock)):
                                    if float(zijdblock[j][0]) == float(PriorRecs[k]["measurement_step_min"]):
                                        start = j
                                    if float(zijdblock[j][0]) == float(PriorRecs[k]["measurement_step_max"]):
                                        end = j
                                pars, errcode = pmag.PintPars(
                                    datablock, araiblock, zijdblock, start, end, accept)
                                pars['measurement_step_unit'] = "K"
                                pars['experiment_type'] = 'LP-PI-TRM'
                                # put in CurrRec, take out of PriorRecs
                                del PriorRecs[k]
                                if errcode != 1:
                                    pars["specimen_lab_field_dc"] = field
                                    pars["specimen_int"] = -1 * \
                                        field*pars["specimen_b"]
                                    pars["er_specimen_name"] = s
                                    if verbose:
                                        print('Saved interpretation: ')
                                    pars, kill = pmag.scoreit(
                                        pars, PmagSpecRec, accept, '', verbose)
                                    pmagplotlib.plot_b(
                                        AZD, araiblock, zijdblock, pars)
                                    if verbose:
                                        pmagplotlib.draw_figs(AZD)
                                    if len(trmblock) > 2:
                                        blab = field
                                        best = pars["specimen_int"]
                                        Bs, TRMs = [], []
                                        for trec in trmblock:
                                            Bs.append(
                                                float(trec['treatment_dc_field']))
                                            TRMs.append(
                                                float(trec['measurement_magn_moment']))
                                        # calculate best fit parameters through TRM acquisition data, and get new banc
                                        NLpars = nlt.NLtrm(
                                            Bs, TRMs, best, blab, 0)
                                        Mp, Bp = [], []
                                        for k in range(int(max(Bs)*1e6)):
                                            Bp.append(float(k)*1e-6)
                                            # predicted NRM for this field
                                            npred = nlt.TRM(
                                                Bp[-1], NLpars['xopt'][0], NLpars['xopt'][1])
                                            Mp.append(npred)
                                        pmagplotlib.plot_trm(
                                            AZD['TRM'], Bs, TRMs, Bp, Mp, NLpars, trec['magic_experiment_name'])
                                        PmagSpecRec['specimen_int'] = NLpars['banc']
                                        if verbose:
                                            print('Banc= ', float(
                                                NLpars['banc'])*1e6)
                                            pmagplotlib.draw_figs(AZD)
                                    mpars = pmag.domean(
                                        araiblock[1], start, end, 'DE-BFL')
                                    if verbose:
                                        print('pTRM direction= ', '%7.1f' % (mpars['specimen_dec']), ' %7.1f' % (
                                            mpars['specimen_inc']), ' MAD:', '%7.1f' % (mpars['specimen_mad']))
                                    if AniSpec != "":
                                        CpTRM = pmag.Dir_anis_corr(
                                            [mpars['specimen_dec'], mpars['specimen_inc']], AniSpec)
                                        AniSpecRec = pmag.doaniscorr(
                                            PmagSpecRec, AniSpec)
                                        if verbose:
                                            print('Anisotropy corrected TRM direction= ', '%7.1f' % (
                                                CpTRM[0]), ' %7.1f' % (CpTRM[1]))
                                            print('Anisotropy corrected intensity= ', float(
                                                AniSpecRec['specimen_int'])*1e6)
                                else:
                                    print('error on specimen ', s)
                        except:
                            pass
                    if verbose and found == 0:
                        print('    None found :(  ')
                if spc != "":
                    if BEG != "":
                        pars, errcode = pmag.PintPars(
                            datablock, araiblock, zijdblock, BEG, END, accept)
                        pars['measurement_step_unit'] = "K"
                        pars["specimen_lab_field_dc"] = field
                        pars["specimen_int"] = -1*field*pars["specimen_b"]
                        pars["er_specimen_name"] = s
                        pars['specimen_grade'] = ''  # ungraded
                        pmagplotlib.plot_b(AZD, araiblock, zijdblock, pars)
                        if verbose:
                            pmagplotlib.draw_figs(AZD)
                        if len(trmblock) > 2:
                            if inlt == 0:
                                inlt = 1
                            blab = field
                            best = pars["specimen_int"]
                            Bs, TRMs = [], []
                            for trec in trmblock:
                                Bs.append(float(trec['treatment_dc_field']))
                                TRMs.append(
                                    float(trec['measurement_magn_moment']))
                            # calculate best fit parameters through TRM acquisition data, and get new banc
                            NLpars = nlt.NLtrm(Bs, TRMs, best, blab, 0)
    #
                            Mp, Bp = [], []
                            for k in range(int(max(Bs)*1e6)):
                                Bp.append(float(k)*1e-6)
                                # predicted NRM for this field
                                npred = nlt.TRM(
                                    Bp[-1], NLpars['xopt'][0], NLpars['xopt'][1])
                    files = {}
                    for key in AZD.keys():
                        files[key] = s+'_'+key+fmt
                    pmagplotlib.save_plots(AZD, files, dpi=dpi)
                    sys.exit()
                if verbose:
                    ans = 'b'
                    while ans != "":
                        print("""
               s[a]ve plot, set [b]ounds for calculation, [d]elete current interpretation, [p]revious, [s]ample, [q]uit:
               """)
                        ans = input('Return for next specimen \n')
                        if ans == "":
                            specimen += 1
                        if ans == "d":
                            save_redo(PriorRecs, inspec)
                            CurrRec = []
                            pmagplotlib.plot_arai_zij(
                                AZD, araiblock, zijdblock, s, units[0])
                            if verbose:
                                pmagplotlib.draw_figs(AZD)
                        if ans == 'a':
                            files = {}
                            for key in AZD.keys():
                                files[key] = "LO:_"+locname+'_SI:_'+PmagSpecRec['er_site_name'] + \
                                    '_SA:_' + \
                                    PmagSpecRec['er_sample_name'] + \
                                    '_SP:_'+s+'_CO:_s_TY:_'+key+fmt
                            pmagplotlib.save_plots(AZD, files)
                            ans = ""
                        if ans == 'q':
                            print("Good bye")
                            sys.exit()
                        if ans == 'p':
                            specimen = specimen - 1
                            backup = 1
                            ans = ""
                        if ans == 's':
                            keepon = 1
                            spec = input(
                                'Enter desired specimen name (or first part there of): ')
                            while keepon == 1:
                                try:
                                    specimen = sids.index(spec)
                                    keepon = 0
                                except:
                                    tmplist = []
                                    for qq in range(len(sids)):
                                        if spec in sids[qq]:
                                            tmplist.append(sids[qq])
                                    print(specimen, " not found, but this was: ")
                                    print(tmplist)
                                    spec = input('Select one or try again\n ')
                            ans = ""
                        if ans == 'b':
                            if end == 0 or end >= len(zijdblock):
                                end = len(zijdblock)-1
                            GoOn = 0
                            while GoOn == 0:
                                answer = input(
                                    'Enter index of first point for calculation: ['+str(start)+']  ')
                                try:
                                    start = int(answer)
                                    answer = input(
                                        'Enter index  of last point for calculation: ['+str(end)+']  ')
                                    end = int(answer)
                                    if start >= 0 and start < len(zijdblock)-2 and end > 0 and end < len(zijdblock) or start >= end:
                                        GoOn = 1
                                    else:
                                        print("Bad endpoints - try again! ")
                                        start, end = 0, len(zijdblock)
                                except ValueError:
                                    print("Bad endpoints - try again! ")
                                    start, end = 0, len(zijdblock)
                            s = sids[specimen]
                            pars, errcode = pmag.PintPars(
                                datablock, araiblock, zijdblock, start, end, accept)
                            pars['measurement_step_unit'] = "K"
                            pars["specimen_lab_field_dc"] = field
                            pars["specimen_int"] = -1*field*pars["specimen_b"]
                            pars["er_specimen_name"] = s
                            pars, kill = pmag.scoreit(
                                pars, PmagSpecRec, accept, '', 0)
                            PmagSpecRec['specimen_scat'] = pars['specimen_scat']
                            PmagSpecRec['specimen_frac'] = '%5.3f' % (
                                pars['specimen_frac'])
                            PmagSpecRec['specimen_gmax'] = '%5.3f' % (
                                pars['specimen_gmax'])
                            PmagSpecRec["measurement_step_min"] = '%8.3e' % (
                                pars["measurement_step_min"])
                            PmagSpecRec["measurement_step_max"] = '%8.3e' % (
                                pars["measurement_step_max"])
                            PmagSpecRec["measurement_step_unit"] = "K"
                            PmagSpecRec["specimen_int_n"] = '%i' % (
                                pars["specimen_int_n"])
                            PmagSpecRec["specimen_lab_field_dc"] = '%8.3e' % (
                                pars["specimen_lab_field_dc"])
                            PmagSpecRec["specimen_int"] = '%9.4e ' % (
                                pars["specimen_int"])
                            PmagSpecRec["specimen_b"] = '%5.3f ' % (
                                pars["specimen_b"])
                            PmagSpecRec["specimen_q"] = '%5.1f ' % (
                                pars["specimen_q"])
                            PmagSpecRec["specimen_f"] = '%5.3f ' % (
                                pars["specimen_f"])
                            PmagSpecRec["specimen_fvds"] = '%5.3f' % (
                                pars["specimen_fvds"])
                            PmagSpecRec["specimen_b_beta"] = '%5.3f' % (
                                pars["specimen_b_beta"])
                            PmagSpecRec["specimen_int_mad"] = '%7.1f' % (
                                pars["specimen_int_mad"])
                            PmagSpecRec["specimen_Z"] = '%7.1f' % (
                                pars["specimen_Z"])
                            PmagSpecRec["specimen_gamma"] = '%7.1f' % (
                                pars["specimen_gamma"])
                            PmagSpecRec["specimen_grade"] = pars["specimen_grade"]
                            if pars["method_codes"] != "":
                                tmpcodes = pars["method_codes"].split(":")
                                for t in tmpcodes:
                                    if t.strip() not in methcodes:
                                        methcodes.append(t.strip())
                            PmagSpecRec["specimen_dec"] = '%7.1f' % (
                                pars["specimen_dec"])
                            PmagSpecRec["specimen_inc"] = '%7.1f' % (
                                pars["specimen_inc"])
                            PmagSpecRec["specimen_tilt_correction"] = '-1'
                            PmagSpecRec["specimen_direction_type"] = 'l'
                            # this is redundant, but helpful - won't be imported
                            PmagSpecRec["direction_type"] = 'l'
                            PmagSpecRec["specimen_int_dang"] = '%7.1f ' % (
                                pars["specimen_int_dang"])
                            PmagSpecRec["specimen_drats"] = '%7.1f ' % (
                                pars["specimen_drats"])
                            PmagSpecRec["specimen_drat"] = '%7.1f ' % (
                                pars["specimen_drat"])
                            PmagSpecRec["specimen_int_ptrm_n"] = '%i ' % (
                                pars["specimen_int_ptrm_n"])
                            PmagSpecRec["specimen_rsc"] = '%6.4f ' % (
                                pars["specimen_rsc"])
                            PmagSpecRec["specimen_md"] = '%i ' % (
                                int(pars["specimen_md"]))
                            if PmagSpecRec["specimen_md"] == '-1':
                                PmagSpecRec["specimen_md"] = ""
                            PmagSpecRec["specimen_b_sigma"] = '%5.3f ' % (
                                pars["specimen_b_sigma"])
                            if "IE-TT" not in methcodes:
                                methcodes.append("IE-TT")
                            methods = ""
                            for meth in methcodes:
                                methods = methods+meth+":"
                            PmagSpecRec["magic_method_codes"] = methods[:-1]
                            PmagSpecRec["specimen_description"] = comment
                            PmagSpecRec["magic_software_packages"] = version_num
                            pmagplotlib.plot_arai_zij(
                                AZD, araiblock, zijdblock, s, units[0])
                            pmagplotlib.plot_b(AZD, araiblock, zijdblock, pars)
                            if verbose:
                                pmagplotlib.draw_figs(AZD)
                            if len(trmblock) > 2:
                                blab = field
                                best = pars["specimen_int"]
                                Bs, TRMs = [], []
                                for trec in trmblock:
                                    Bs.append(
                                        float(trec['treatment_dc_field']))
                                    TRMs.append(
                                        float(trec['measurement_magn_moment']))
                                # calculate best fit parameters through TRM acquisition data, and get new banc
                                NLpars = nlt.NLtrm(Bs, TRMs, best, blab, 0)
                                Mp, Bp = [], []
                                for k in range(int(max(Bs)*1e6)):
                                    Bp.append(float(k)*1e-6)
                                    # predicted NRM for this field
                                    npred = nlt.TRM(
                                        Bp[-1], NLpars['xopt'][0], NLpars['xopt'][1])
                                    Mp.append(npred)
                                pmagplotlib.plot_trm(
                                    AZD['TRM'], Bs, TRMs, Bp, Mp, NLpars, trec['magic_experiment_name'])
                                if verbose:
                                    print(
                                        'Non-linear TRM corrected intensity= ', float(NLpars['banc'])*1e6)
                            if verbose:
                                pmagplotlib.draw_figs(AZD)
                            pars["specimen_lab_field_dc"] = field
                            pars["specimen_int"] = -1*field*pars["specimen_b"]
                            pars, kill = pmag.scoreit(
                                pars, PmagSpecRec, accept, '', verbose)
                            saveit = input(
                                "Save this interpretation? [y]/n \n")
                            if saveit != 'n':
                                # put back an interpretation
                                PriorRecs.append(PmagSpecRec)
                                specimen += 1
                                save_redo(PriorRecs, inspec)
                            ans = ""
                elif plots == 1:
                    specimen += 1
                    if fmt != ".pmag":
                        files = {}
                        for key in AZD.keys():
                            files[key] = "LO:_"+locname+'_SI:_'+PmagSpecRec['er_site_name']+'_SA:_' + \
                                PmagSpecRec['er_sample_name'] + \
                                '_SP:_'+s+'_CO:_s_TY:_'+key+'_'+fmt
                        if pmagplotlib.isServer:
                            black = '#000000'
                            purple = '#800080'
                            titles = {}
                            titles['deremag'] = 'DeReMag Plot'
                            titles['zijd'] = 'Zijderveld Plot'
                            titles['arai'] = 'Arai Plot'
                            AZD = pmagplotlib.add_borders(
                                AZD, titles, black, purple)
                        pmagplotlib.save_plots(AZD, files, dpi=dpi)
    #                   pmagplotlib.combineFigs(s,files,3)
                    else:  # save in pmag format
                        script = "grep "+s+" output.mag | thellier -mfsi"
                        script = script+' %8.4e' % (field)
                        min = '%i' % ((pars["measurement_step_min"]-273))
                        Max = '%i' % ((pars["measurement_step_max"]-273))
                        script = script+" "+min+" "+Max
                        script = script+" |plotxy;cat mypost >>thellier.ps\n"
                        pltf.write(script)
                        pmag.domagicmag(outf, MeasRecs)
        if len(CurrRec) > 0:
            for rec in CurrRec:
                PriorRecs.append(rec)
        CurrRec = []
    if plots != 1 and verbose:
        ans = input(" Save last plot? 1/[0] ")
        if ans == "1":
            if fmt != ".pmag":
                files = {}
                for key in AZD.keys():
                    files[key] = s+'_'+key+fmt
                pmagplotlib.save_plots(AZD, files, dpi=dpi)
        else:
            print("\n Good bye\n")
            sys.exit()
        if len(CurrRec) > 0:
            PriorRecs.append(CurrRec)  # put back an interpretation
        if len(PriorRecs) > 0:
            save_redo(PriorRecs, inspec)
            print('Updated interpretations saved in ', inspec)
    if verbose:
        print("Good bye")


Instruction:
How would you implement a function in Python 3 that
names nrm_specimens_magic.py Note: this program has been deprecated and is not maintained DESCRIPTION converts NRM data in a measurements type file to geographic and tilt corrected data in a specimens type file SYNTAX nrm_specimens_magic.py [-h][command line options] OPTIONS: -h prints the help message and quits -f MFILE: specify input file -fsa SFILE: specify samples format file [with orientations] -F PFILE: specify output file -A do not average replicate measurements -crd [g, t]: specify coordinate system ([g]eographic or [t]ilt adjusted) NB: you must have the SFILE in this directory DEFAULTS MFILE: measurements.txt PFILE: nrm_specimens.txt SFILE: samples.txt coord: g average replicate measurements?: YES

Response:
def main():
    """
        NAME
            nrm_specimens_magic.py
            Note: this program has been deprecated and is not maintained

        DESCRIPTION
            converts NRM data in a measurements type file to
            geographic and tilt corrected data in a specimens type file

        SYNTAX
           nrm_specimens_magic.py [-h][command line options]

        OPTIONS:
            -h prints the help message and quits
            -f MFILE: specify input file
            -fsa SFILE: specify samples format file [with orientations]
            -F PFILE: specify output file
            -A  do not average replicate measurements
            -crd [g, t]: specify coordinate system ([g]eographic or [t]ilt adjusted)
                 NB: you must have the  SFILE in this directory

        DEFAULTS
            MFILE: measurements.txt
            PFILE: nrm_specimens.txt
            SFILE: samples.txt
            coord: g
            average replicate measurements?: YES

    """
#
#   define some variables
#
    beg, end, pole, geo, tilt, askave, save = 0, 0, [], 0, 0, 0, 0
    samp_file = 1
    args = sys.argv
    geo, tilt, orient = 0, 0, 0
    doave = 1
    user, comment, doave, coord = "", "", 1, "g"
    geo, orient = 1, 1

    dir_path = '.'
    if "-h" in args:
        print(main.__doc__)
        sys.exit()
    if '-WD' in sys.argv:
        ind = sys.argv.index('-WD')
        dir_path = sys.argv[ind + 1]
    meas_file = dir_path + "/measurements.txt"
    spec_file = dir_path + "/specimens.txt"
    samp_file = dir_path + "/samples.txt"
    out_file = dir_path + "/nrm_specimens.txt"
    if "-A" in args:
        doave = 0
    if "-f" in args:
        ind = args.index("-f")
        meas_file = sys.argv[ind + 1]
    if "-F" in args:
        ind = args.index("-F")
        out_file = dir_path + '/' + sys.argv[ind + 1]
    speclist = []
    if "-fsa" in args:
        ind = args.index("-fsa")
        samp_file = dir_path + '/' + sys.argv[ind + 1]
    if "-crd" in args:
        ind = args.index("-crd")
        coord = sys.argv[ind + 1]
        if coord == "t":
            tilt, orient, geo = 1, 1, 1
#
# read in data
    #
    meas_data = pd.read_csv(meas_file, header=1, sep='\t')
    meas_data = meas_data[meas_data['method_codes'].str.contains(
        'LT-NO') == True]  # fish out NRM data
    meas_data = meas_data[['specimen', 'dir_dec', 'dir_inc']]
    meas_data = meas_data.dropna(subset=['dir_dec', 'dir_inc'])
    meas_data = pd.DataFrame(meas_data)
#   import samples  for orientation info
#
##
    if orient == 1:
        spec_data = pd.read_csv(spec_file, header=1, sep='\t')
        spec_data = spec_data[['specimen', 'sample']]
        meas_data = pd.merge(meas_data, spec_data,
                             how='inner', on=['specimen'])
        samp_data = pd.read_csv(samp_file, header=1, sep='\t')
    #
    sids = meas_data.specimen.unique()  # list of specimen names
    #
    #
    NrmSpecRecs = []
    for spec in sids:
        gdec, ginc, bdec, binc = "", "", "", ""
        this_spec_data = meas_data[meas_data.specimen.str.contains(spec)]
        this_sample = this_spec_data['sample'].iloc[-1]
        this_sample_data = samp_data[samp_data['sample'].str.contains(
            this_sample)]
        this_sample_data = this_sample_data.to_dict('records')
        for m in this_spec_data.to_dict('records'):
            NrmSpecRec = {'specimen': spec, 'sample': this_sample}
            if coord == 'g':
                NrmSpecRec['dir_tilt_correction'] = '0'
            elif coord == 't':
                NrmSpecRec['dir_tilt_correction'] = '100'
            else:
                NrmSpecRec['dir_tilt_correction'] = '-1'
            if not orient:
                NrmSpecRec['dir_dec'] = m['dir_dec']
                NrmSpecRec['dir_inc'] = m['dir_inc']
                NrmSpecRec['method_codes'] = 'SO-NO'
                NrmSpecRecs.append(NrmSpecRec)
            else:  # do geographic correction
                # get the azimuth
                or_info, az_type = pmag.get_orient(
                    this_sample_data, this_sample, data_model=3)
                if 'azimuth' in or_info.keys() and or_info['azimuth'] != "":
                    azimuth = or_info['azimuth']
                    dip = or_info['dip']
                    gdec, ginc = pmag.dogeo(
                        m['dir_dec'], m['dir_inc'], azimuth, dip)
                    if tilt:
                        # try tilt correction
                        if 'bed_dip' in or_info.keys() and or_info['bed_dip'] != "":
                            bed_dip = or_info['bed_dip']
                            bed_dip_dir = or_info['bed_dip_direction']
                            bdec, binc = pmag.dogeo(
                                gdec, ginc, bed_dip_dir, bed_dip)
                            NrmSpecRec['dir_dec'] = bdec
                            NrmSpecRec['dir_inc'] = binc
                            NrmSpecRec['method_codes'] = az_type
                            NrmSpecRecs.append(NrmSpecRec)
                        else:
                            print('no bedding orientation data for ', spec)

                    else:
                        NrmSpecRec['dir_dec'] = gdec
                        NrmSpecRec['dir_inc'] = ginc
                        NrmSpecRec['method_codes'] = az_type
                        NrmSpecRecs.append(NrmSpecRec)
                else:
                    print('no geo orientation data for ', spec)

    pmag.magic_write(out_file, NrmSpecRecs, 'specimens')


Instruction:
Write a Python 3 script for
running the interpreter and returns the unique identifier for the interpreter.

Response:
def run_interpreter(self):
        """
        Run thellier_auto_interpreter
        """

        import random
        import copy

        start_time = time.time()
        #------------------------------------------------
        # Clean work directory
        #------------------------------------------------

        # self.write_acceptance_criteria_to_file()
        try:
            shutil.rmtree(os.path.join(self.WD, "thellier_interpreter"))
        except:
            pass

        try:
            os.mkdir(os.path.join(self.WD, "thellier_interpreter"))
        except:
            pass

        #------------------------------------------------
        # Intialize interpreter output files:
        # Prepare header for "Thellier_auto_interpretation.all.txt"
        # All the acceptable interpretation are saved in this file
        #------------------------------------------------

        # sort acceptance criteria
        self.specimen_criteria = []
        for crit in list(self.acceptance_criteria.keys()):
            if 'category' in list(self.acceptance_criteria[crit].keys()):
                if self.acceptance_criteria[crit]['category'] == "IE-SPEC":
                    if self.acceptance_criteria[crit]['value'] != -999:
                        self.specimen_criteria.append(crit)

        # sort acceptance criteria
        sample_criteria = []
        for crit in list(self.acceptance_criteria.keys()):
            if 'category' in list(self.acceptance_criteria[crit].keys()):
                if self.acceptance_criteria[crit]['category'] == "IE-SAMP":
                    if self.acceptance_criteria[crit]['value'] != -999:
                        sample_criteria.append(crit)

        # sort acceptance criteria
        site_criteria = []
        for crit in list(self.acceptance_criteria.keys()):
            if 'category' in list(self.acceptance_criteria[crit].keys()):
                if self.acceptance_criteria[crit]['category'] == "thellier_gui":
                    if self.acceptance_criteria[crit]['value'] != -999:
                        site_criteria.append(crit)

        # sort acceptance criteria
        thellier_gui_criteria = []
        for crit in list(self.acceptance_criteria.keys()):
            if 'category' in list(self.acceptance_criteria[crit].keys()):
                if self.acceptance_criteria[crit]['category'] == "thellier_gui":
                    if self.acceptance_criteria[crit]['value'] != -999:
                        thellier_gui_criteria.append(crit)

        #----------------------------

        # log file
        self.thellier_interpreter_log = open(
            self.WD + "/" + "/thellier_interpreter//thellier_interpreter.log", 'w')
        self.thellier_interpreter_log.write("-I- Start auto interpreter\n")

        # "all grade A interpretation
        thellier_interpreter_all = open(
            self.WD + "/thellier_interpreter/thellier_interpreter_all.txt", 'w')
        thellier_interpreter_all.write("tab\tpmag_specimens\n")
        String = "er_specimen_name\tmeasurement_step_min\tmeasurement_step_max\tspecimen_lab_field_dc_uT\tspecimen_int_corr_anisotropy\tspecimen_int_corr_nlt\tspecimen_int_corr_cooling_rate\tspecimen_int_uT\t"
        # + ["specimen_b"] + ['specimen_cm_x'] + ['specimen_cm_y']:
        for crit in self.specimen_criteria:
            String = String + crit + "\t"
        String = String[:-1] + "\n"
        thellier_interpreter_all.write(String)

        # specimen_bound
        Fout_specimens_bounds = open(
            self.WD + "/thellier_interpreter/thellier_interpreter_specimens_bounds.txt", 'w')
        String = "acceptance criteria:\n"
        for crit in self.specimen_criteria:
            String = String + crit + "\t"
        Fout_specimens_bounds.write(String[:-1] + "\n")
        String = ""
        for crit in self.specimen_criteria:
            if type(self.acceptance_criteria[crit]['value']) == str:
                string = self.acceptance_criteria[crit]['value']
            elif type(self.acceptance_criteria[crit]['value']) == bool:
                string = str(self.acceptance_criteria[crit]['value'])
            elif type(self.acceptance_criteria[crit]['value']) == int or type(self.acceptance_criteria[crit]['value']) == float:
                if self.acceptance_criteria[crit]['decimal_points'] == -999:
                    string = "{:.3f}".format(self.acceptance_criteria[crit]['value'])
                else:
                    string = "{:.{}f}".format(self.acceptance_criteria[crit]['value'],
                                             self.acceptance_criteria[crit]['decimal_points'])

            else:
                string=""

            String=String+"%s\t"%string
        Fout_specimens_bounds.write(String[:-1]+"\n")
        Fout_specimens_bounds.write("--------------------------------\n")
        Fout_specimens_bounds.write("er_sample_name\ter_specimen_name\tspecimen_int_corr_anisotropy\tAnisotropy_code\tspecimen_int_corr_nlt\tspecimen_int_corr_cooling_rate\tspecimen_lab_field_dc_uT\tspecimen_int_min_uT\tspecimen_int_max_uT\tWARNING\n")

        #----------------------------------

        criteria_string = "acceptance criteria:\n"
        for crit in self.specimen_criteria + sample_criteria + site_criteria + thellier_gui_criteria:
            criteria_string = criteria_string + crit + "\t"
        criteria_string = criteria_string[:-1] + "\n"
        for crit in self.specimen_criteria + sample_criteria + site_criteria + thellier_gui_criteria:
            if type(self.acceptance_criteria[crit]['value']) == str:
                string = self.acceptance_criteria[crit]['value']
            elif type(self.acceptance_criteria[crit]['value']) == bool:
                string = str(self.acceptance_criteria[crit]['value'])
            elif type(self.acceptance_criteria[crit]['value']) == int or type(self.acceptance_criteria[crit]['value']) == float:
                if self.acceptance_criteria[crit]['decimal_points'] == -999:
                    string = "%.3e" % (
                        float(self.acceptance_criteria[crit]['value']))
                else:
                    string = "{:.{}f}".format(self.acceptance_criteria[crit]['value'],
                                              self.acceptance_criteria[crit]['decimal_points'])
            else:
                string = ""

            criteria_string = criteria_string + "%s\t" % string
        criteria_string = criteria_string[:-1] + "\n"
        criteria_string = criteria_string + "---------------------------------\n"

        # STDEV-OPT output files
        if self.acceptance_criteria['interpreter_method']['value'] == 'stdev_opt':
            self.Fout_STDEV_OPT_redo = open(
                self.WD + "/thellier_interpreter/thellier_interpreter_STDEV-OPT_redo", 'w')
            self.Fout_STDEV_OPT_specimens = open(
                self.WD + "/thellier_interpreter/thellier_interpreter_STDEV-OPT_specimens.txt", 'w')

            self.Fout_STDEV_OPT_specimens.write("tab\tpmag_specimens\n")
            String = "er_sample_name\ter_specimen_name\tspecimen_int_uT\tmeasurement_step_min\tmeasurement_step_min\tspecimen_lab_field_dc\tAnisotropy_correction_factor\tNLT_correction_factor\tCooling_rate_correction_factor\t"
            for crit in self.specimen_criteria:
                String = String + crit + "\t"
            self.Fout_STDEV_OPT_specimens.write(String[:-1] + "\n")

            if self.acceptance_criteria['average_by_sample_or_site']['value'] == 'sample':
                self.Fout_STDEV_OPT_samples = open(
                    self.WD + "/thellier_interpreter/thellier_interpreter_STDEV-OPT_samples.txt", 'w')
                self.Fout_STDEV_OPT_samples.write(criteria_string)
                self.Fout_STDEV_OPT_samples.write(
                    "er_sample_name\tsample_int_n\tsample_int_uT\tsample_int_sigma_uT\tsample_int_sigma_perc\tsample_int_min_uT\tsample_int_min_sigma_uT\tsample_int_max_uT\tsample_int_max_sigma_uT\tsample_int_interval_uT\tsample_int_interval_perc\tWarning\n")
            else:
                self.Fout_STDEV_OPT_sites = open(
                    self.WD + "/thellier_interpreter/thellier_interpreter_STDEV-OPT_sites.txt", 'w')
                self.Fout_STDEV_OPT_sites.write(criteria_string)
                self.Fout_STDEV_OPT_sites.write(
                    "er_site_name\tsite_int_n\tsite_int_uT\tsite_int_sigma_uT\tsite_int_sigma_perc\tsite_int_min_uT\tsite_int_min_sigma_uT\tsite_int_max_uT\tsite_int_max_sigma_uT\tsite_int_interval_uT\tsite_int_interval_perc\tWarning\n")

        # simple bootstrap output files
        # Dont supports site yet!

        if self.acceptance_criteria['interpreter_method']['value'] == 'bs':
            Fout_BS_samples = open(
                self.WD + "/thellier_interpreter/thellier_interpreter_BS_samples.txt", 'w')
            Fout_BS_samples.write(criteria_string)
            # Fout_BS_samples.write("---------------------------------\n")
            Fout_BS_samples.write(
                "er_sample_name\tsample_int_n\tsample_int_uT\tsample_int_68_low\tsample_int_68_high\tsample_int_95_low\tsample_int_95_high\tsample_int_sigma_uT\tsample_int_sigma_perc\tWARNING\n")
        # parameteric bootstrap output files

        if self.acceptance_criteria['interpreter_method']['value'] == 'bs_par':
            Fout_BS_PAR_samples = open(
                self.WD + "/thellier_interpreter/thellier_interpreter_BS-PAR_samples.txt", 'w')
            Fout_BS_PAR_samples.write(criteria_string)
            # Fout_BS_PAR_samples.write("---------------------------------\n")
            Fout_BS_PAR_samples.write(
                "er_sample_name\tsample_int_n\tsample_int_uT\tsample_int_68_low\tsample_int_68_high\tsample_int_95_low\tsample_int_95_high\tsample_int_sigma_uT\tsample_int_sigma_perc\tWARNING\n")

        self.thellier_interpreter_log.write(
            "-I- using paleointenisty statistics:\n")
        self.thellier_interpreter_log.write(criteria_string)

        #------------------------------------------------

        specimens_list = list(self.Data.keys())
        specimens_list.sort()
        self.thellier_interpreter_log.write(
            "-I- Found %i specimens\n" % (len(specimens_list)))

        # try:
        All_grade_A_Recs = {}
        print('-I- Running through specimens:')
        for s in specimens_list:
            self.thellier_interpreter_log.write(
                "-I- doing now specimen %s\n" % s)
            self.Data[s]['pars'] = {}
            self.Data[s]['pars']['lab_dc_field'] = self.Data[s]['lab_dc_field']
            self.Data[s]['pars']['er_specimen_name'] = s
            self.Data[s]['pars']['er_sample_name'] = self.Data_hierarchy['specimens'][s]
            temperatures = self.Data[s]['t_Arai']

            # check that all temperatures are in right order:
            ignore_specimen = False
            for t in range(len(temperatures) - 1):
                if float(temperatures[t + 1]) < float(temperatures[t]):
                    self.thellier_interpreter_log.write(
                        "-W- Found problem in the temperature order of specimen %s. skipping specimen\n" % (s))
                    ignore_specimen = True
            if ignore_specimen:
                continue
            if self.acceptance_criteria['specimen_int_n']['value'] != -999:
                specimen_int_n = min(
                    3, int(self.acceptance_criteria['specimen_int_n']['value']))
            else:
                specimen_int_n = 3
            #-------------------------------------------------
            # loop through all possible tmin,tmax and check if pass criteria
            #-------------------------------------------------
            # print s
            for tmin_i in range(len(temperatures) - specimen_int_n + 1):
                # check if to include NRM
                # print temperatures
                # print  self.acceptance_criteria['include_nrm']['value']
                if self.acceptance_criteria['include_nrm']['value'] == -999:
                    # print " Its False"
                    if temperatures[tmin_i] == 273:
                        continue
                    #    print "ignoring NRM",tmin_i,temperatures[tmin_i]
                # print tmin_i
                for tmax_i in range(tmin_i + specimen_int_n - 1, len(temperatures)):
                    # print tmax_i
                    # print len(temperatures)
                    tmin = temperatures[tmin_i]
                    tmax = temperatures[tmax_i]
                    pars = thellier_gui_lib.get_PI_parameters(
                        self.Data, self.acceptance_criteria, self.preferences, s, tmin, tmax, self.GUI_log, THERMAL, MICROWAVE)
                    if not pars:  # error with getting pars
                        message_string = '-W- Problem in SPD. Could not calculate any parameters for {} with tmin: {} and tmax {}. Check data for typos, make sure temperatures are correct, etc.'.format(
                            s, tmin, tmax)
                        self.thellier_interpreter_log.write(
                            message_string + "\n")
                        continue
                    if 'NLT_specimen_correction_factor' not in list(pars.keys()):
                        # problem in get_PI_parameters (probably with
                        # tmin/zdata).  can't run specimen
                        message_string = '-W- Problem in get_PI_parameters. Could not get all parameters for {} with tmin: {} and tmax: {}. Check data for typos, make sure temperatures are correct, etc.'.format(
                            s, tmin, tmax)
                        self.thellier_interpreter_log.write(
                            message_string + "\n")
                        continue
                    pars = thellier_gui_lib.check_specimen_PI_criteria(
                        pars, self.acceptance_criteria)
                    #-------------------------------------------------
                    # check if pass the criteria
                    #-------------------------------------------------

                    if 'specimen_fail_criteria' in list(pars.keys()) and len(pars['specimen_fail_criteria']) > 0:
                        # Fail:
                        message_string = "-I- specimen %s (%.0f-%.0f) FAIL on: " % (s, float(
                            pars["measurement_step_min"]) - 273, float(pars["measurement_step_max"]) - 273)
                        for parameter in pars['specimen_fail_criteria']:
                            if "scat" not in parameter:
                                message_string = message_string + \
                                    parameter + "= %f,  " % pars[parameter]
                            else:
                                message_string = message_string + parameter + \
                                    "= %s,  " % str(pars[parameter])

                        self.thellier_interpreter_log.write(
                            message_string + "\n")
                    elif 'specimen_fail_criteria' in list(pars.keys()) and len(pars['specimen_fail_criteria']) == 0:

                        # PASS:
                        message_string = "-I- specimen %s (%.0f-%.0f) PASS" % (s, float(
                            pars["measurement_step_min"]) - 273, float(pars["measurement_step_max"]) - 273)
                        self.thellier_interpreter_log.write(
                            message_string + "\n")

                        #----------------------------------------------------
                        # Save all the grade A interpretation in thellier_interpreter_all.txt
                        #----------------------------------------------------

                        String = s + "\t"
                        String = String + \
                            "%.0f\t" % (
                                float(pars["measurement_step_min"]) - 273.)
                        String = String + \
                            "%.0f\t" % (
                                float(pars["measurement_step_max"]) - 273.)
                        String = String + \
                            "%.0f\t" % (float(pars["lab_dc_field"]) * 1e6)

                        if "Anisotropy_correction_factor" in list(pars.keys()):
                            String = String + \
                                "%.2f\t" % float(
                                    pars["Anisotropy_correction_factor"])
                        else:
                            String = String + "-\t"
                        if float(pars["NLT_specimen_correction_factor"]) != -999:
                            String = String + \
                                "%.2f\t" % float(
                                    pars["NLT_specimen_correction_factor"])
                        else:
                            String = String + "-\t"
                        if float(pars["specimen_int_corr_cooling_rate"]) != -999 and float(pars["specimen_int_corr_cooling_rate"]) != -1:
                            String = String + \
                                "%.2f\t" % float(
                                    pars["specimen_int_corr_cooling_rate"])
                        else:
                            String = String + "-\t"
                        Bancient = float(pars['specimen_int_uT'])
                        String = String + "%.1f\t" % (Bancient)
                        # + ["specimen_b"] + ["specimen_cm_x"] + ["specimen_cm_y"]:
                        for key in self.specimen_criteria:
                            if type(pars[key]) == str:
                                String = String + pars[key] + "\t"
                            else:
                                String = String + \
                                    "%.3e" % (float(pars[key])) + "\t"
                        String = String[:-1] + "\n"

                        thellier_interpreter_all.write(String)

                        #-------------------------------------------------
                        # save 'acceptable' (grade A) specimen interpretaion
                        # All_grade_A_Recs={}
                        # All_grade_A_Recs[specimen_name]["tmin,tmax"]={PI pars sorted in dictionary}
                        #-------------------------------------------------

                        if s not in list(All_grade_A_Recs.keys()):
                            All_grade_A_Recs[s] = {}
                        new_pars = {}
                        for k in list(pars.keys()):
                            new_pars[k] = pars[k]
                        TEMP = "%.0f,%.0f" % (float(
                            pars["measurement_step_min"]) - 273, float(pars["measurement_step_max"]) - 273)
                        All_grade_A_Recs[s][TEMP] = new_pars

        specimens_list = list(All_grade_A_Recs.keys())
        specimens_list.sort()
        Grade_A_samples = {}
        Grade_A_sites = {}
        Redo_data_specimens = {}

        #--------------------------------------------------------------
        # specimens bound file
        #--------------------------------------------------------------

        for s in specimens_list:

            sample = self.Data_hierarchy['specimens'][s]
            site = thellier_gui_lib.get_site_from_hierarchy(
                sample, self.Data_hierarchy)
            B_lab = float(self.Data[s]['lab_dc_field']) * 1e6
            B_min, B_max = 1e10, 0.
            NLT_factor_min, NLT_factor_max = 1e10, 0.
            all_B_tmp_array = []

            for TEMP in list(All_grade_A_Recs[s].keys()):
                pars = All_grade_A_Recs[s][TEMP]
                if "AC_anisotropy_type" in list(pars.keys()):
                    AC_correction_factor = pars["Anisotropy_correction_factor"]
                    AC_correction_type = pars["AC_anisotropy_type"]
                    WARNING = ""
                    if "AC_WARNING" in list(pars.keys()):
                        WARNING = WARNING + pars["AC_WARNING"]
                else:
                    AC_correction_factor = 1.
                    AC_correction_type = "-"
                    WARNING = "WARNING: No anisotropy correction"

                B_anc = pars['specimen_int_uT']

                if B_anc < B_min:
                    B_min = B_anc
                if B_anc > B_max:
                    B_max = B_anc
                if pars["NLT_specimen_correction_factor"] != -1:
                    NLT_f = pars['NLT_specimen_correction_factor']
                    if NLT_f < NLT_factor_min:
                        NLT_factor_min = NLT_f
                    if NLT_f > NLT_factor_max:
                        NLT_factor_max = NLT_f

                # sort by samples
                #------------------------------------------------------------

                if cb.not_null(sample, False):
                    if sample not in list(Grade_A_samples.keys()):
                        Grade_A_samples[sample] = {}
                    if s not in list(Grade_A_samples[sample].keys()) and len(All_grade_A_Recs[s]) > 0:
                        Grade_A_samples[sample][s] = []
                    if cb.not_null(B_anc, False):
                        Grade_A_samples[sample][s].append(B_anc)

                # sort by sites
                #------------------------------------------------------------

                if cb.not_null(site, False):
                    if site not in list(Grade_A_sites.keys()):
                        Grade_A_sites[site] = {}
                    if s not in list(Grade_A_sites[site].keys()) and len(All_grade_A_Recs[s]) > 0:
                        Grade_A_sites[site][s] = []
                    if cb.not_null(B_anc, False):
                        Grade_A_sites[site][s].append(B_anc)

                # ? check
                #------------------------------------------------------------

                if s not in list(Redo_data_specimens.keys()):
                    Redo_data_specimens[s] = {}

            # write to specimen_bounds
            #----------------------------------------------------------------

            if pars["NLT_specimen_correction_factor"] != -1:
                NLT_factor = "%.2f" % (NLT_factor_max)
            else:
                NLT_factor = "-"

            if pars["specimen_int_corr_cooling_rate"] != -1 and pars["specimen_int_corr_cooling_rate"] != -999:
                CR_factor = "%.2f" % (
                    float(pars["specimen_int_corr_cooling_rate"]))
            else:
                CR_factor = "-"
            if 'cooling_rate_data' in list(self.Data[s].keys()):
                if 'CR_correction_factor_flag' in list(self.Data[s]['cooling_rate_data'].keys()):
                    if self.Data[s]['cooling_rate_data']['CR_correction_factor_flag'] != "calculated":
                        if "inferred" in self.Data[s]['cooling_rate_data']['CR_correction_factor_flag']:
                            WARNING = WARNING + ";" + "cooling rate correction inferred from sister specimens"
                        if "alteration" in self.Data[s]['cooling_rate_data']['CR_correction_factor_flag']:
                            WARNING = WARNING + ";" + "cooling rate experiment failed alteration"
                        if "bad" in self.Data[s]['cooling_rate_data']['CR_correction_factor_flag']:
                            WARNING = WARNING + ";" + "cooling rate experiment failed"

            if AC_correction_type == "-":
                AC_correction_factor_to_print = "-"
            else:
                AC_correction_factor_to_print = "%.2f" % AC_correction_factor

            String = "%s\t%s\t%s\t%s\t%s\t%s\t%.1f\t%.1f\t%.1f\t%s\n"\
                % (sample, s, AC_correction_factor_to_print, AC_correction_type, NLT_factor, CR_factor, B_lab, B_min, B_max, WARNING)
            Fout_specimens_bounds.write(String)

        #--------------------------------------------------------------
        # Find the STDEV-OPT 'best mean':
        # the interprettaions that give
        # the minimum standrad deviation (perc!)
        # not nesseserily the standrad deviation in microT
        #
        #--------------------------------------------------------------

        # Sort all grade A interpretation

        samples = list(Grade_A_samples.keys())
        samples.sort()

        sites = list(Grade_A_sites.keys())
        sites.sort()

        #--------------------------------------------------------------
        # thellier-interpreter can work by averaging specimens by sample (default)
        # or by averaging specimens by site
        #--------------------------------------------------------------

        if self.acceptance_criteria['average_by_sample_or_site']['value'] == 'sample':
            self.Grade_A_sorted = copy.deepcopy(Grade_A_samples)

        else:
            self.Grade_A_sorted = copy.deepcopy(Grade_A_sites)

        self.clean_workspace()

        samples_or_sites = list(self.Grade_A_sorted.keys())
        samples_or_sites.sort()
        # print Grade_A_sorted
        for sample_or_site in samples_or_sites:
            if len(list(self.Grade_A_sorted[sample_or_site].keys())) == 1:
                specimen = list(self.Grade_A_sorted[sample_or_site].keys())[0]
                self.choose_interpretation_max_frac(All_grade_A_Recs, specimen)
            else:
                self.thellier_interpreter_pars = self.calc_upper_level_mean(
                    self.Grade_A_sorted, All_grade_A_Recs, sample_or_site)
                self.update_data_with_interpreter_pars(
                    self.Grade_A_sorted, All_grade_A_Recs, sample_or_site, self.thellier_interpreter_pars)
                self.update_files_with_intrepretation(
                    self.Grade_A_sorted, All_grade_A_Recs, sample_or_site, self.thellier_interpreter_pars)
        self.thellier_interpreter_log.write("-I- Statistics:\n")
        self.thellier_interpreter_log.write(
            "-I- number of specimens analzyed = %i\n" % len(specimens_list))
        self.thellier_interpreter_log.write(
            "-I- number of sucsessful 'acceptable' specimens = %i\n" % len(list(All_grade_A_Recs.keys())))

        runtime_sec = time.time() - start_time
        m, s = divmod(runtime_sec, 60)
        h, m = divmod(m, 60)
        self.thellier_interpreter_log.write(
            "-I- runtime hh:mm:ss is " + "%d:%02d:%02d\n" % (h, m, s))
        if len(specimens_list) != 0:
            self.thellier_interpreter_log.write(
                "-I- runtime per specimen: %.1f seconds" % (float(runtime_sec) / len(specimens_list)))

        self.thellier_interpreter_log.write("-I- Finished sucsessfuly.\n")
        self.thellier_interpreter_log.write("-I- DONE\n")

        # close all files

        self.thellier_interpreter_log.close()
        thellier_interpreter_all.close()
        Fout_specimens_bounds.close()
        if self.acceptance_criteria['interpreter_method']['value'] == 'stdev_opt':
            self.Fout_STDEV_OPT_redo.close()
            self.Fout_STDEV_OPT_specimens.close()
        if self.acceptance_criteria['interpreter_method']['value'] == 'stdev_opt':
            if self.acceptance_criteria['average_by_sample_or_site']['value'] == 'sample':
                self.Fout_STDEV_OPT_samples.close()
            else:
                self.Fout_STDEV_OPT_sites.close()

        if self.acceptance_criteria['interpreter_method']['value'] == 'bs':
            Fout_BS_samples.close()

        if self.acceptance_criteria['interpreter_method']['value'] == 'bs_par':
            Fout_BS_PAR_samples.close()
        # try:
        #    os.system('\a')
        # except:
        #    pass
        return True, len(specimens_list)


Instruction:
How would you explain what the following Python 3 function does
def find_close_value(self, LIST, value):
        '''
        take a LIST and find the nearest value in LIST to 'value'
        '''
        diff = inf
        for a in LIST:
            if abs(value - a) < diff:
                diff = abs(value - a)
                result = a
        return(result)

Response: take a LIST and find the nearest value in LIST to value