docs: def sufar4(ascfile, meas_output='measurements.txt', aniso_output='rmag_anisotropy.txt',
             spec_infile=None, spec_outfile='specimens.txt', samp_outfile='samples.txt',
             site_outfile='sites.txt', specnum=0, sample_naming_con='1', user="",
             locname="unknown", instrument='', static_15_position_mode=False,
             dir_path='.', input_dir_path='', data_model_num=3):
      """
      Converts ascii files generated by SUFAR ver.4.0 to MagIC files
  
      Parameters
      ----------
      ascfile : str
          input ASC file, required
      meas_output : str
          measurement output filename, default "measurements.txt"
      aniso_output : str
          anisotropy output filename, MagIC 2 only, "rmag_anisotropy.txt"
      spec_infile : str
          specimen infile, default None
      spec_outfile : str
          specimen outfile, default "specimens.txt"
      samp_outfile : str
          sample outfile, default "samples.txt"
      site_outfile : str
          site outfile, default "sites.txt"
      specnum : int
          number of characters to designate a specimen, default 0
      sample_naming_con : str
          sample/site naming convention, default '1', see info below
      user : str
          user name, default ""
      locname : str
          location name, default "unknown"
      instrument : str
          instrument name, default ""
      static_15_position_mode : bool
          specify static 15 position mode - default False (is spinning)
      dir_path : str
          output directory, default "."
      input_dir_path : str
          input file directory IF different from dir_path, default ""
      data_model_num : int
          MagIC data model 2 or 3, default 3
  
      Returns
      --------
      type - Tuple : (True or False indicating if conversion was sucessful, file name written)
  
      Info
      --------
      Sample naming convention:
          [1] XXXXY: where XXXX is an arbitrary length site designation and Y
              is the single character sample designation.  e.g., TG001a is the
              first sample from site TG001.    [default]
          [2] XXXX-YY: YY sample from site XXXX (XXX, YY of arbitary length)
          [3] XXXX.YY: YY sample from site XXXX (XXX, YY of arbitary length)
          [4-Z] XXXX[YYY]:  YYY is sample designation with Z characters from site XXX
          [5] site name = sample name
          [6] site name entered in site_name column in the orient.txt format input file  -- NOT CURRENTLY SUPPORTED
          [7-Z] [XXX]YYY:  XXX is site designation with Z characters from samples  XXXYYY
  
      """
  
      citation = 'This study'
      cont = 0
      Z = 1
      AniRecSs, AniRecs, SpecRecs, SampRecs, SiteRecs, MeasRecs = [], [], [], [], [], []
      isspec = '0'
      spin = 0
      data_model_num = int(float(data_model_num))
  
      # set defaults for MagIC 2
      if data_model_num == 2:
          if meas_output == 'measurements.txt':
              meas_output = 'magic_measurements.txt'
          if spec_outfile == 'specimens.txt':
              spec_outfile = 'er_specimens.txt'
          if samp_outfile == 'samples.txt':
              samp_outfile = 'er_samples.txt'
          if site_outfile == 'sites.txt':
              site_outfile = 'er_sites.txt'
  
      # set column names for MagIC 3
      spec_name_col = 'specimen'
      samp_name_col = 'sample'
      site_name_col = 'site'
      loc_name_col = 'location'
      citation_col = 'citations'
      method_col = 'method_codes'
      site_description_col = 'description'
      expedition_col = 'expedition_name'
      instrument_col = 'instrument_codes'
      experiment_col = 'experiments'
      analyst_col = 'analysts'
      quality_col = 'quality'
      aniso_quality_col = 'result_quality'
      meas_standard_col = 'standard'
      meas_description_col = 'description'
      aniso_type_col = 'aniso_type'
      aniso_unit_col = 'aniso_s_unit'
      aniso_n_col = 'aniso_s_n_measurements'
      azimuth_col = 'azimuth'
      spec_volume_col = 'volume'
      samp_dip_col = 'dip'
      bed_dip_col = 'bed_dip'
      bed_dip_direction_col = 'bed_dip_direction'
      chi_vol_col = 'susc_chi_volume'
      aniso_sigma_col = 'aniso_s_sigma'
      aniso_unit_col = 'aniso_s_unit'
      aniso_tilt_corr_col = 'aniso_tilt_correction'
      meas_table_name = 'measurements'
      spec_table_name = 'specimens'
      samp_table_name = 'samples'
      site_table_name = 'sites'
  
      # set column names for MagIC 2
      if data_model_num == 2:
          spec_name_col = 'er_specimen_name'
          samp_name_col = 'er_sample_name'
          site_name_col = 'er_site_name'
          loc_name_col = 'er_location_name'
          citation_col = 'er_citation_names'
          method_col = 'magic_method_codes'
          site_description_col = 'site_description'
          expedition_col = 'er_expedition_name'
          instrument_col = 'magic_instrument_codes'
          experiment_col = 'magic_experiment_names'
          analyst_col = 'er_analyst_mail_names'
          quality_col = 'measurement_flag'
          aniso_quality_col = 'anisotropy_flag'
          meas_standard_col = 'measurement_standard'
          meas_description_col = 'measurement_description'
          aniso_type_col = 'anisotropy_type'
          aniso_unit_col = 'anisotropy_unit'
          aniso_n_col = 'anisotropy_n'
          azimuth_col = 'sample_azimuth'
          spec_volume_col = 'specimen_volume'
          samp_dip_col = 'sample_dip'
          bed_dip_col = 'sample_bed_dip'
          bed_dip_direction_col = 'sample_bed_dip_direction'
          chi_vol_col = 'measurement_chi_volume'
          aniso_sigma_col = 'anisotropy_sigma'
          aniso_unit_col = 'anisotropy_unit'
          aniso_tilt_corr_col = 'anisotropy_tilt_correction'
          meas_table_name = 'magic_measurements'
          spec_table_name = 'er_specimens'
          samp_table_name = 'er_samples'
          site_table_name = 'er_sites'
  
      # create full path for files
      input_dir_path, output_dir_path = pmag.fix_directories(input_dir_path, dir_path)
      ascfile = os.path.join(input_dir_path, ascfile)
      aniso_output = os.path.join(output_dir_path, aniso_output)
      # initialized but not used
      meas_output = os.path.join(output_dir_path, meas_output)
  
      spec_outfile = os.path.join(output_dir_path, spec_outfile)
      samp_outfile = os.path.join(output_dir_path, samp_outfile)
      site_outfile = os.path.join(output_dir_path, site_outfile)
  
      if "4" in sample_naming_con:
          if "-" not in sample_naming_con:
              print("option [4] must be in form 4-Z where Z is an integer")
              return False, "option [4] must be in form 4-Z where Z is an integer"
          else:
              Z = sample_naming_con.split("-")[1]
              sample_naming_con = "4"
      if "7" in sample_naming_con:
          if "-" not in sample_naming_con:
              print("option [7] must be in form 7-Z where Z is an integer")
              return False, "option [7] must be in form 7-Z where Z is an integer"
          else:
              Z = sample_naming_con.split("-")[1]
              sample_naming_con = "7"
  
      if static_15_position_mode:
          spin = 0
  
      if spec_infile:
          if os.path.isfile(os.path.join(input_dir_path, str(spec_infile))):
              # means an er_specimens.txt file has been provided with sample,
              # site, location (etc.) info
              isspec = '1'
  
      specnum = int(specnum)
  
      if isspec == "1":
          specs, file_type = pmag.magic_read(spec_infile)
  
      specnames, sampnames, sitenames = [], [], []
      # if '-new' not in sys.argv: # see if there are already specimen,sample, site files lying around
      #    try:
      #        SpecRecs,file_type=pmag.magic_read(input_dir_path+'/er_specimens.txt')
      #        for spec in SpecRecs:
      #            if spec['er_specimen_name'] not in specnames:
      #                specnames.append(samp['er_specimen_name'])
      #    except:
      #        SpecRecs,specs=[],[]
      #    try:
      #        SampRecs,file_type=pmag.magic_read(input_dir_path+'/er_samples.txt')
      #        for samp in SampRecs:
      #            if samp['er_sample_name'] not in sampnames:sampnames.append(samp['er_sample_name'])
      #    except:
      #        sampnames,SampRecs=[],[]
      #    try:
      #        SiteRecs,file_type=pmag.magic_read(input_dir_path+'/er_sites.txt')
      #        for site in SiteRecs:
      #            if site['er_site_names'] not in sitenames:sitenames.append(site['er_site_name'])
      #    except:
      #        sitenames,SiteRecs=[],[]
  
      try:
          file_input = open(ascfile, 'r')
      except:
          print('Error opening file: ', ascfile)
          return False, 'Error opening file: {}'.format(ascfile)
      Data = file_input.readlines()
      file_input.close()
      k = 0
      while k < len(Data):
          line = Data[k]
          words = line.split()
          if "ANISOTROPY" in words:  # first line of data for the spec
              MeasRec, AniRec, SpecRec, SampRec, SiteRec = {}, {}, {}, {}, {}
              specname = words[0]
              AniRec[spec_name_col] = specname
              if isspec == "1":
                  for spec in specs:
                      if spec[spec_name_col] == specname:
                          AniRec[samp_name_col] = spec[samp_name_col]
                          AniRec[site_name_col] = spec[site_name_col]
                          AniRec[loc_name_col] = spec[loc_name_col]
                          break
              elif isspec == "0":
                  if specnum != 0:
                      sampname = specname[:-specnum]
                  else:
                      sampname = specname
                  AniRec[samp_name_col] = sampname
                  SpecRec[spec_name_col] = specname
                  SpecRec[samp_name_col] = sampname
                  SampRec[samp_name_col] = sampname
                  SiteRec[samp_name_col] = sampname
                  SiteRec[site_description_col] = 's'
                  if sample_naming_con != "9":
                      AniRec[site_name_col] = pmag.parse_site(
                          AniRec[samp_name_col], sample_naming_con, Z)
                      SpecRec[site_name_col] = pmag.parse_site(
                          AniRec[samp_name_col], sample_naming_con, Z)
                      SampRec[site_name_col] = pmag.parse_site(
                          AniRec[samp_name_col], sample_naming_con, Z)
                      SiteRec[site_name_col] = pmag.parse_site(
                          AniRec[samp_name_col], sample_naming_con, Z)
                  else:
                      AniRec[site_name_col] = specname
                      SpecRec[site_name_col] = specname
                      SampRec[site_name_col] = specname
                      SiteRec[site_name_col] = specname
                      pieces = specname.split('-')
                      AniRec[expedition_col] = pieces[0]
                      SpecRec[expedition_col] = pieces[0]
                      SampRec[expedition_col] = pieces[0]
                      SiteRec[expedition_col] = pieces[0]
                      location = pieces[1]
                  AniRec[loc_name_col] = locname
                  SpecRec[loc_name_col] = locname
                  SampRec[loc_name_col] = locname
                  SiteRec[loc_name_col] = locname
                  AniRec[citation_col] = "This study"
                  SpecRec[citation_col] = "This study"
                  SampRec[citation_col] = "This study"
                  SiteRec[citation_col] = "This study"
              AniRec[citation_col] = "This study"
              AniRec[instrument_col] = instrument
              AniRec[method_col] = "LP-X:AE-H:LP-AN-MS"
              AniRec[experiment_col] = specname + ":" + "LP-AN-MS"
              AniRec[analyst_col] = user
              for key in list(AniRec.keys()):
                  MeasRec[key] = AniRec[key]
              if data_model_num == 2:
                  MeasRec['magic_experiment_name'] = AniRec.get('magic_experiment_names', '')
                  if 'magic_experiment_names' in MeasRec:
                      MeasRec.pop('magic_experiment_names')
              if data_model_num == 3:
                  MeasRec['experiment'] = AniRec.get('experiments', '')
                  if 'experiments' in MeasRec:
                      MeasRec.pop('experiments')
              MeasRec[quality_col] = 'g'
              AniRec[aniso_quality_col] = 'g'
              MeasRec[meas_standard_col] = 'u'
              MeasRec[meas_description_col] = 'Bulk sucsecptibility measurement'
              AniRec[aniso_type_col] = "AMS"
              AniRec[aniso_unit_col] = "Normalized by trace"
              if spin == 1:
                  AniRec[aniso_n_col] = "192"
              else:
                  AniRec[aniso_n_col] = "15"
          if 'Azi' in words and isspec == '0':
              az = float(words[1])
              P1 = float(words[4])
              P2 = float(words[5])
              P3 = float(words[6])
              # P4 relates to a fabric or bedding measurement -- not dealt with
              # here
              P4 = float(words[7])
              az = az + P1 * 360. / 12. - P3 * 360. / 12.
              if az >= 360:
                  az = az - 360
              elif az <= -360:
                  az = az + 360
              labaz = az
              SampRec[azimuth_col] = str(round(az, 1))
          if 'Dip' in words:
              # convert actual volume to m^3 from cm^3
              SpecRec[spec_volume_col] = '%8.3e' % (float(words[10]) * 1e-6)
              dip = float(words[1])
              if P2 == 90:
                  dip = dip - 90.
              labdip = dip
              SampRec[samp_dip_col] = str(round(dip, 1))
          if 'T1' in words and 'F1' in words:
              k += 2  # read in fourth line down
              line = Data[k]
              rec = line.split()
              dd = rec[1].split('/')
              dip_direction = int(dd[0]) + 90
              SampRec[bed_dip_direction_col] = '%i' % (dip_direction)
              SampRec[bed_dip_col] = dd[1]
              bed_dip = float(dd[1])
          if "Mean" in words:
              k += 4  # read in fourth line down
              line = Data[k]
              rec = line.split()
              MeasRec[chi_vol_col] = rec[1]
              sigma = .01 * float(rec[2]) / 3.
              AniRec[aniso_sigma_col] = '%7.4f' % (sigma)
              AniRec[aniso_unit_col] = 'SI'
          if "factors" in words:
              k += 4  # read in second line down
              line = Data[k]
              rec = line.split()
          if "Specimen" in words:  # first part of specimen data
              # eigenvalues sum to unity - not 3
              s1_val = '%7.4f' % (float(words[5]) / 3.)
              s2_val = '%7.4f' % (float(words[6]) / 3.)
              s3_val = '%7.4f' % (float(words[7]) / 3.)
              k += 1
              line = Data[k]
              rec = line.split()
              # eigenvalues sum to unity - not 3
              s4_val= '%7.4f' % (float(rec[5]) / 3.)
              s5_val = '%7.4f' % (float(rec[6]) / 3.)
              s6_val = '%7.4f' % (float(rec[7]) / 3.)
              # parse for data model 2
              if data_model_num == 2:
                  AniRec['anisotropy_s1'] = s1_val
                  AniRec['anisotropy_s2'] = s2_val
                  AniRec['anisotropy_s3'] = s3_val
                  AniRec['anisotropy_s4'] = s4_val
                  AniRec['anisotropy_s5'] = s5_val
                  AniRec['anisotropy_s6'] = s6_val
              # parse for data model 3
              else:
                  vals = (s1_val, s2_val, s3_val, s4_val, s5_val, s6_val)
                  AniRec['aniso_s'] = ":".join([v.strip() for v in vals])
              #
              AniRec[aniso_tilt_corr_col] = '-1'
              AniRecs.append(AniRec)
              AniRecG, AniRecT = {}, {}
              for key in list(AniRec.keys()):
                  AniRecG[key] = AniRec[key]
              for key in list(AniRec.keys()):
                  AniRecT[key] = AniRec[key]
              sbar = []
              sbar.append(float(s1_val))
              sbar.append(float(s2_val))
              sbar.append(float(s3_val))
              sbar.append(float(s4_val))
              sbar.append(float(s5_val))
              sbar.append(float(s6_val))
              sbarg = pmag.dosgeo(sbar, labaz, labdip)
              s1_g = '%12.10f' % (sbarg[0])
              s2_g = '%12.10f' % (sbarg[1])
              s3_g = '%12.10f' % (sbarg[2])
              s4_g = '%12.10f' % (sbarg[3])
              s5_g = '%12.10f' % (sbarg[4])
              s6_g = '%12.10f' % (sbarg[5])
              if data_model_num == 2:
                  AniRecG["anisotropy_s1"] = s1_g
                  AniRecG["anisotropy_s2"] = s2_g
                  AniRecG["anisotropy_s3"] = s3_g
                  AniRecG["anisotropy_s4"] = s4_g
                  AniRecG["anisotropy_s5"] = s5_g
                  AniRecG["anisotropy_s6"] = s6_g
              else:
                  vals = (s1_g, s2_g, s3_g, s4_g, s5_g, s6_g)
                  AniRecG['aniso_s'] = ":".join([v.strip() for v in vals])
              AniRecG[aniso_tilt_corr_col] = '0'
              AniRecs.append(AniRecG)
              if bed_dip != "" and bed_dip != 0:  # have tilt correction
                  sbart = pmag.dostilt(sbarg, dip_direction, bed_dip)
                  s1_t = '%12.10f' % (sbart[0])
                  s2_t = '%12.10f' % (sbart[1])
                  s3_t = '%12.10f' % (sbart[2])
                  s4_t = '%12.10f' % (sbart[3])
                  s5_t = '%12.10f' % (sbart[4])
                  s6_t = '%12.10f' % (sbart[5])
                  if data_model_num == 2:
                      AniRecT["anisotropy_s1"] = s1_t
                      AniRecT["anisotropy_s2"] = s2_t
                      AniRecT["anisotropy_s3"] = s3_t
                      AniRecT["anisotropy_s4"] = s4_t
                      AniRecT["anisotropy_s5"] = s5_t
                      AniRecT["anisotropy_s6"] = s6_t
                  else:
                      vals = (s1_t, s2_t, s3_t, s4_t, s5_t, s6_t)
                      AniRecT["aniso_s"] = ":".join([v.strip() for v in vals])
                  AniRecT[aniso_tilt_corr_col] = '100'
                  AniRecs.append(AniRecT)
              MeasRecs.append(MeasRec)
              if SpecRec[spec_name_col] not in specnames:
                  SpecRecs.append(SpecRec)
                  specnames.append(SpecRec[spec_name_col])
              if SampRec[samp_name_col] not in sampnames:
                  SampRecs.append(SampRec)
                  sampnames.append(SampRec[samp_name_col])
              if SiteRec[site_name_col] not in sitenames:
                  SiteRecs.append(SiteRec)
                  sitenames.append(SiteRec[site_name_col])
          k += 1  # skip to next specimen
  
      pmag.magic_write(meas_output, MeasRecs, meas_table_name)
      print("bulk measurements put in ", meas_output)
      # if isspec=="0":
      SpecOut, keys = pmag.fillkeys(SpecRecs)
      #
      # for MagIC 2, anisotropy records go in rmag_anisotropy
      if data_model_num == 2:
          pmag.magic_write(aniso_output, AniRecs, 'rmag_anisotropy')
          print("anisotropy tensors put in ", aniso_output)
      # for MagIC 3, anisotropy records go in specimens
      if data_model_num == 3:
          full_SpecOut = []
          spec_list = []
          for rec in SpecOut:
              full_SpecOut.append(rec)
              spec_name = rec[spec_name_col]
              if spec_name not in spec_list:
                  spec_list.append(spec_name)
                  ani_recs = pmag.get_dictitem(AniRecs, spec_name_col, spec_name, 'T')
                  full_SpecOut.extend(ani_recs)
  
  
          # FILL KEYS
          full_SpecOut, keys = pmag.fillkeys(full_SpecOut)
      else:
          full_SpecOut = SpecOut
      pmag.magic_write(spec_outfile, full_SpecOut, spec_table_name)
      print("specimen/anisotropy info put in ", spec_outfile)
      SampOut, keys = pmag.fillkeys(SampRecs)
      pmag.magic_write(samp_outfile, SampOut, samp_table_name)
      print("sample info put in ", samp_outfile)
      SiteOut, keys = pmag.fillkeys(SiteRecs)
      pmag.magic_write(site_outfile, SiteOut, site_table_name)
      print("site info put in ", site_outfile)
      return True, meas_output