diff --git a/postpic/analyzer/analyzer.py b/postpic/analyzer/analyzer.py index dcb8142b..3204987f 100644 --- a/postpic/analyzer/analyzer.py +++ b/postpic/analyzer/analyzer.py @@ -89,8 +89,8 @@ class SpeciesIdentifier(PhysicalConstants): 'gold20': True} # unit: amu - _masslistelement = {'H': 1, 'He': 4, 'C': 12, 'N': 14, 'O': 16, 'F': 19, - 'Ne': 20.2, 'Al': 27, 'Si': 28, 'Ar': 40, 'Au': 197} + _masslistelement = {'H': 1, 'He': 4, 'Li': 6.9, 'C': 12, 'N': 14, 'O': 16, 'F': 19, + 'Ne': 20.2, 'Al': 27, 'Si': 28, 'Ar': 40, 'Rb': 85.5, 'Au': 197} @staticmethod def isejected(species): @@ -105,7 +105,8 @@ def ision(cls, species): @classmethod def identifyspecies(cls, species): """ - Returns a dictionary contining particle informations. + Returns a dictionary containing particle informations deduced from + the species name. The following keys in the dictionary will always be present: name species name string mass kg (SI) @@ -125,15 +126,20 @@ def identifyspecies(cls, species): # Regex for parsing ion species name. # See docsting for valid examples - regex = '(?P(.*_)*)(?P(ionc(?P\d+)m(?P\d+)|' \ - 'ionm(?P\d+)c(?P\d+))|(?P[Ee]le[ck]tron)|' \ - '(?P[A-Za-z]+)(?P\d*))(?P[a-z]*)' + regex = '(?P(.*_)*)' \ + '((?P((?!El)[A-Z][a-z]?))(?P\d*)|' \ + '(?P(ionc(?P\d+)m(?P\d+)|ionm(?P\d+)c(?P\d+)))' \ + ')?' \ + '(?P(Plus)*)' \ + '(?P[Ee]le[ck])?' \ + '(?P\w*?)$' r = re.match(regex, s) if r is None: raise Exception('Species ' + str(s) + ' does not match regex name pattern: ' + str(regex)) regexdict = r.groupdict() + # print(regexdict) # recognize anz prae and add dictionary key if regexdict['prae']: @@ -142,44 +148,52 @@ def identifyspecies(cls, species): if not key == '': ret[key] = True - # Name Element + charge state: C1, C6, F2, F9, Au20, Pb34a + # Excluding patterns start here + # 1) Name Element + charge state: C1, C6, F2, F9, Au20, Pb34a if regexdict['elem']: - try: - ret['mass'] = float(cls._masslistelement[regexdict['elem']]) * \ - 1836.2 * cls.me + ret['mass'] = float(cls._masslistelement[regexdict['elem']]) * \ + 1836.2 * cls.me + if regexdict['elem_c'] == '': + ret['charge'] = 0 + else: ret['charge'] = float(regexdict['elem_c']) * cls.qe + ret['ision'] = True + # 2) ionmc like + elif regexdict['ionmc']: + if regexdict['c1']: + ret['mass'] = float(regexdict['m2']) * 1836.2 * cls.me + ret['charge'] = float(regexdict['c1']) * cls.qe + ret['ision'] = True + + if regexdict['c2']: + ret['mass'] = float(regexdict['m1']) * 1836.2 * cls.me + ret['charge'] = float(regexdict['c2']) * cls.qe ret['ision'] = True - except KeyError: - # this pattern will also match, if name is defined in masslist, - # so just ignore if key is not found. - pass + # charge may be given via plus + if regexdict['plus']: + charge = len(regexdict['plus'])/4 * cls.qe + if ret['charge'] == 0: + ret['charge'] = charge + + # Elektron can be appended to any ion name, so overwrite. if regexdict['electron']: ret['mass'] = cls.me ret['charge'] = -1 * cls.qe ret['ision'] = False - if regexdict['c1']: - ret['mass'] = float(regexdict['m2']) * 1836.2 * cls.me - ret['charge'] = float(regexdict['c1']) * cls.qe - ret['ision'] = True - - if regexdict['c2']: - ret['mass'] = float(regexdict['m1']) * 1836.2 * cls.me - ret['charge'] = float(regexdict['c2']) * cls.qe - ret['ision'] = True - # simply added to _masslist and _chargelist # this should not be used anymore - if regexdict['name'] in cls._masslist: - ret['mass'] = float(cls._masslist[regexdict['name']]) * cls.me - if regexdict['name'] in cls._chargelist: - ret['charge'] = float(cls._chargelist[regexdict['name']] * cls.qe) - if regexdict['name'] in cls._isionlist: - ret['ision'] = cls._isionlist[regexdict['name']] + # set only if property is not already set + if 'mass' not in ret and regexdict['suffix'] in cls._masslist: + ret['mass'] = float(cls._masslist[regexdict['suffix']]) * cls.me + if 'charge' not in ret and regexdict['suffix'] in cls._chargelist: + ret['charge'] = float(cls._chargelist[regexdict['suffix']] * cls.qe) + if 'ision' not in ret and regexdict['suffix'] in cls._isionlist: + ret['ision'] = cls._isionlist[regexdict['suffix']] if not (('mass' in ret) and ('charge' in ret) and ('ision' in ret)): - raise Error('species ' + species + ' not recognized.') + raise Exception('species ' + species + ' not recognized.') return ret diff --git a/test/test_analyzer.py b/test/test_analyzer.py index 25f342af..d83f8f5c 100644 --- a/test/test_analyzer.py +++ b/test/test_analyzer.py @@ -39,6 +39,11 @@ def test_identifyspecies_electron(self): self.checke(idfy('ElektronAu2'), 1, -1, False, False, False) self.checke(idfy('ejected_ElektronAu2'), 1, -1, True, False, False) self.checke(idfy('tracer_blahh_electronHe2b'), 1, -1, False, True, False) + self.checke(idfy('tracer_blahh_elecHe2b'), 1, -1, False, True, False) + self.checke(idfy('tracer_blahh_HeElec2b'), 1, -1, False, True, False) + self.checke(idfy('Elec'), 1, -1, False, False, False) + self.checke(idfy('Elec2x'), 1, -1, False, False, False) + self.checke(idfy('Electrons'), 1, -1, False, False, False) def test_identifyspecies_praefix(self): x = pa.identifyspecies('a_b_c_xxx_tracer_h_w_33_He5_O3x2') @@ -52,5 +57,32 @@ def test_identifyspecies_praefix(self): self.assertEqual(x['He5'], True) self.checkion(x, 16,3, False, True, True) + def test_identifyspecies_extendedsyntax(self): + idfy = pa.identifyspecies + self.checkion(idfy('H'), 1, 0, False, False, True) + self.checkion(idfy('HPlus'), 1, 1, False, False, True) + self.checkion(idfy('H1Plus'), 1, 1, False, False, True) + #self.checkion(idfy('Hplus'), 1, 1, False, False, True) + self.checkion(idfy('HePlusPlus'), 4, 2, False, False, True) + self.checkion(idfy('He2Plus'), 4, 2, False, False, True) + self.checkion(idfy('HPlus'), 1, 1, False, False, True) + self.checke(idfy('HElectron'), 1, -1, False, False, False) + self.checke(idfy('HElectrons'), 1, -1, False, False, False) + self.checke(idfy('HElec'), 1, -1, False, False, False) + self.checke(idfy('HPlusElec'), 1, -1, False, False, False) + self.checke(idfy('HePlusPluselectrons'), 1, -1, False, False, False) + + def test_falsefriends(self): + idfy = pa.identifyspecies + # careful: the last one is an uncharged ion + self.checke(idfy('HElectron'), 1, -1, False, False, False) + self.checke(idfy('HeElectron'), 1, -1, False, False, False) + self.checke(idfy('Heelectron'), 1, -1, False, False, False) + self.checkion(idfy('Helectron'), 4, 0, False, False, True) + # Tiny differences may decide about Ne or electrons + self.checke(idfy('NElectron'), 1, -1, False, False, False) + self.checkion(idfy('Nelectron'), 20.2, 0, False, False, True) + self.checke(idfy('Neelectron'), 1, -1, False, False, False) + if __name__ == '__main__': unittest.main()