docs: def aquireMs1CalibrationData(msrunContainer, specfile, siiArrays=None,
      lockMass=None, **kwargs):
      """Aquire mass error data, observed vs expected m/z, for calibration of MS1
      ion m/z values. Expected m/z values can be of ambient ions with known exact
      masses and from identified precursor masses of peptide spectrum matching
      results.
  
      :param msrunContainer: intance of :class:`maspy.core.MsrunContainer`
      :param specfile: filename of an ms-run file, used to extract mass error data
      :param siiArrays: optional, a dictionary of numpy.arrays
          Must provide the keys "obsMz" (observed precursor m/z), "excMz" (exact
          calculated m/z of the identified peptide) and "precursorId" (the scan id
          of the MS1 that preceeded the respective MSn scan).
      :param lockMass: None, True or a list of lock mass m/z values
          If ``None`` lock masses are not used to aquire calibration data. If
          ``True`` use the seven predefined lock mass values. Else use the
          specified lock mass m/z values.
      :param scanRange: a list of positive and negative int values
          When using MSn spectrum identifications for aquiring calibration data
          the m/z value of the peptide precursor is used to find the corresponding
          ion m/z value in the preceeding MS1 scan. By adding positive and
          negative integers to the ``scanRange`` parameter the subsequent and
          preceeding MS1 scans are also used to aquire calibration data from the
          same peptide precursor. By default "[-1, 0, 1]".
      :param massTolerance: float or int
          The maximal allowed deviation for matching two masses. By default
          "10 * 1e-6" which corresponds to 10ppm.
      :param toleranceMode: "relative" or "absolute"
          Specifies how the ``massTolerance`` value is applied, by default
          "relative
      :param topIntMatches: bool, by default False
      :param useTopIntIons: bool,  by default False
  
      :returns: {'siId': numpy.array([str, ...]),
                 'rt': numpy.array([float, ...]),
                 'obsMz': numpy.array([float, ...]),
                 'excMz': numpy.array([float, ...]),
                 'relDev': numpy.array([float, ...]),
                 'absDev': numpy.array([float, ...]),
                 'int': numpy.array([float, ...])
                 'source': numpy.array(['psm' or 'lock'])
                 }
      """
      scanRange = kwargs.get('scanRange', [-1, 0, 1])
      massTolerance = kwargs.get('massTolerance', 10*1e-6)
      toleranceMode = kwargs.get('toleranceMode', 'relative')
      topIntMatches = kwargs.get('topIntMatches', False)
      useTopIntIons = kwargs.get('useTopIntIons', False)
  
      ms1Arrays = msrunContainer.getArrays(['rt'], specfiles=specfile, sort='rt',
                                           selector=lambda si: si.msLevel==1
                                           )
      ms1Arrays['calibrationMz'] = [list() for x in range(len(ms1Arrays['id']))]
  
      if lockMass is not None:
          if lockMass == True: #Use default lock mass values
              lockMass = [445.12002, 519.13882, 593.15761, 667.1764,
                          536.16536, 610.18416, 684.20295]
          lockMassTuples = [(lockMassMz, lockMassMz, 'lock') for lockMassMz in lockMass]
          for ms1ArrayPos in range(len(ms1Arrays['id'])):
              ms1Arrays['calibrationMz'][ms1ArrayPos].extend(lockMassTuples)
  
      if siiArrays is not None:
          precursorArrayLookup = {__: _ for _, __ in enumerate(ms1Arrays['id'])}
          for obsMz, excMz, precursorId in zip(siiArrays['obsMz'],
                                               siiArrays['excMz'],
                                               siiArrays['precursorId']
                                               ):
              #find array position of the precursor scan
              precursorArrayPos = precursorArrayLookup[precursorId]
              #also look for the peptide precursor ions in earlier and later MS1
              #scans by modifying the precursorArrayPos according to the numbers
              #in "scanRange"
              for posModifier in scanRange:
                  _arrayPos = precursorArrayPos + posModifier
                  try:
                      ms1Arrays['calibrationMz'][_arrayPos].append((obsMz, excMz, 'psm'))
                  except IndexError:
                      #An IndexError can occur because of the "scanRange"
                      #extension at the end and the beginning of the MS1 scans
                      pass
  
      calibrationDataMs1 = {_: [] for _ in ['siId', 'rt', 'obsMz', 'excMz', 'iit',
                                            'source', 'relDev', 'absDev', 'int'
                                            ]
                            }
      for siId, rtMs1, calibrationMz in zip(ms1Arrays['id'],
                                            ms1Arrays['rt'],
                                            ms1Arrays['calibrationMz']
                                            ):
          if len(calibrationMz) == 0:
              continue
  
          ionMzListMs1 = msrunContainer.saic[specfile][siId].arrays['mz']
          ionIntListMs1 = msrunContainer.saic[specfile][siId].arrays['i']
  
          if useTopIntIons:
              ionIntMask = ionIntListMs1.argsort()[::-1][:useTopIntIons]
              ionMzListMs1 = ionMzListMs1[ionIntMask]
              ionIntListMs1 = ionIntListMs1[ionIntMask]
  
          currCalibrationData = ddict(list)
          for obsMz, excMz, source in calibrationMz:
              limHigh = obsMz * (1+massTolerance)
              limLow = obsMz * (1-massTolerance)
              pL = bisect.bisect_left(ionMzListMs1, limLow)
              pH = bisect.bisect_right(ionMzListMs1, limHigh)
  
              if pH - pL <= 0:
                  continue
              ionMatchMask = abs(ionMzListMs1[pL:pH] - obsMz).argmin()
              ms1Mz = ionMzListMs1[pL:pH][ionMatchMask]
              ms1Int = ionIntListMs1[pL:pH][ionMatchMask]
  
              #TODO: rel dev calculation changed, test dataFit functions!!!
              relDevObs = (1 - ms1Mz / obsMz)
              absDevObs = obsMz - ms1Mz
              relDevExc = (1 - ms1Mz / excMz)
              absDevExc = excMz - ms1Mz
              if abs(relDevObs) <= massTolerance:
                  currCalibrationData['siId'].append(siId)
                  currCalibrationData['rt'].append(rtMs1)
                  currCalibrationData['obsMz'].append(ms1Mz)
                  currCalibrationData['excMz'].append(excMz)
                  currCalibrationData['relDev'].append(relDevExc)
                  currCalibrationData['absDev'].append(absDevExc)
                  currCalibrationData['int'].append(ms1Int)
                  currCalibrationData['iit'].append(msrunContainer.sic[specfile][siId].iit)
                  currCalibrationData['source'].append(source)
          if len(currCalibrationData['siId']) == 0:
              continue
          for key in currCalibrationData.keys():
              calibrationDataMs1[key].extend(currCalibrationData[key])
  
      # Convert calibration data into numpy arrays
      for key in calibrationDataMs1.keys():
          calibrationDataMs1[key] = numpy.array(calibrationDataMs1[key])
  
      return calibrationDataMs1