Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b8f501f
Create a symbol to Z dictionary
php1ic Sep 21, 2025
69d62d1
Update AME parser to use read_fwf
php1ic Sep 26, 2025
c940a7d
Fix bug after moving to a match statement
php1ic Sep 26, 2025
f85f34b
Convert AME reaction1 to read_fwf parsing
php1ic Sep 26, 2025
6b3af94
Remove new line from end of file
php1ic Sep 27, 2025
72c1628
Convert AME reaction2 to read_fwf
php1ic Sep 27, 2025
25eadd9
Update AME mass table parsing test and fix bugs
php1ic Sep 27, 2025
e42bb4d
Update AME reaction 1 tests
php1ic Sep 27, 2025
54941dd
Update AME reaction 2 tests
php1ic Sep 27, 2025
be16c1b
Add 1983 AME mass table parsing functionality
php1ic Sep 27, 2025
62172ed
Add 1983 AME reaction 1 file parsing
php1ic Sep 27, 2025
01e940e
Add 1983 AME reaction 2 file parsing
php1ic Sep 27, 2025
2a4a557
Add the files from 1983, 1993 and 1995
php1ic Sep 27, 2025
5cecfc6
Add tests for AME 2016 data
php1ic Sep 27, 2025
0e254ed
Add tests for AME 2012 data
php1ic Sep 27, 2025
6100cce
Add tests for AME 2003 data
php1ic Sep 27, 2025
915e4f4
Add tests for 1995 AME data
php1ic Sep 27, 2025
6722fc4
Add tests for 1993 AME file parsing
php1ic Sep 28, 2025
150ab2e
Split AME tests by year
php1ic Sep 28, 2025
4447c41
Remove nested match statement
php1ic Sep 28, 2025
2b3962c
Update NUBASE parsing and tests
php1ic Sep 28, 2025
6b455d3
Use a better class name after recent updates
php1ic Sep 30, 2025
1171bbe
Rename the file to match the new class name
php1ic Sep 30, 2025
5a1647d
Update tests to match ElementConverter class
php1ic Sep 30, 2025
0701f5c
Add the year to the parsed dataframes
php1ic Sep 30, 2025
05f3e56
Add condition to remove repeated header in 2020 rct2 file
php1ic Oct 1, 2025
9c8be5f
Remove debug print message
php1ic Oct 1, 2025
2fbdaa4
Add the table year to the nubase data and update tests
php1ic Oct 1, 2025
1871561
Update the top level mass table class
php1ic Oct 1, 2025
3d46c42
Delete old debug comment
php1ic Oct 1, 2025
b62ba3f
Update README
php1ic Oct 1, 2025
c343800
Update CI to include latest version of python
php1ic Oct 1, 2025
96fc638
Latest ubuntu on github runner doesn't have 3.14
php1ic Oct 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 105 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ All data should, however, be accurate.

## Mass tables

The data files released by the papers linked below are used to create the mass tables read by this code
The data files released by the papers linked below are used to create the mass tables read by this code.
There was no AME data published in 1997, but the 1995 AME matches the 1997 NUBASE according to section 4, "The tables" on P31 of [these proceedings](https://www.google.co.uk/books/edition/Atomic_Physics_at_Accelerators_Mass_Spec/3AbsCAAAQBAJ?hl=en).
As a result the 1997 NUBASE data is referred to as being from 1995 for simplicity when merging data.
- [AME1983](https://doi.org/10.1016/0375-9474(85)90283-0)
- [AME1993](https://doi.org/10.1016/0375-9474(93)90024-R)
- [AME1995](https://doi.org/10.1016/0375-9474(95)00445-9) + [NUBASE1997](https://doi.org/10.1016/S0375-9474(97)00482-X)
- [AME2003](https://doi.org/10.1016/j.nuclphysa.2003.11.002) + [NUBASE2003](https://doi.org/10.1016/j.nuclphysa.2003.11.001)
- [AME2012](https://doi.org/10.1088/1674-1137/36/12/002) + [NUBASE2012](https://doi.org/10.1088/1674-1137/36/12/001)
- [AME2016](https://doi.org/10.1088/1674-1137/41/3/030002) + [NUBASE2016](https://doi.org/10.1088/1674-1137/41/3/030001)
Expand All @@ -30,3 +35,102 @@ The package is available on the Python Package Index so can be installed via pip
pip install nuclearmasses
```

Or you can clone the latest version from github
```bash
git clone https://github.com/php1ic/nuclearmasses
```

## Usage

Once installed or cloned, the data is available as a single dataframe indexed on the mass table year
```python
>>> from nuclearmasses.mass_table import MassTable
>>> df = MassTable().full_data
```
You can then interrogate, or extract, what ever information you want.
For example, how has the mass excess and it's accuracy changed overtime for 190Re according to the AME
```python
>>> df[(df['A'] == 190) & (df['Symbol'] == 'Re')][['AMEMassExcess', 'AMEMassExcessError']]
AMEMassExcess AMEMassExcessError
TableYear
1983 -35536.605 200.029
1993 -35557.789 145.549
1995 -35568.032 212.151
2003 -35566.326 149.248
2012 -35634.992 70.542
2016 -35635.830 70.852
2020 -35583.015 4.870
```
Or how do the mass excess of gold vary across the isotropic chain according to NUBASE in the most recent table for both experimentally measured and theoretical values
```python
>>> df.query("TableYear == 2020 and Symbol == 'Au'")[['A', 'NUBASEMassExcess', 'NUBASEMassExcessError', 'Experimental']]
A NUBASEMassExcess NUBASEMassExcessError Experimental
TableYear
2020 168 2530.0 400.0 False
2020 169 -1790.0 300.0 False
2020 170 -3700.0 200.0 False
2020 171 -7562.0 21.0 True
2020 172 -9320.0 60.0 True
2020 173 -12832.0 23.0 True
2020 174 -14060.0 100.0 False
2020 175 -17400.0 40.0 True
2020 176 -18520.0 30.0 True
2020 177 -21546.0 10.0 True
2020 178 -22303.0 10.0 True
2020 179 -24989.0 12.0 True
2020 180 -25626.0 5.0 True
2020 181 -27871.0 20.0 True
2020 182 -28304.0 19.0 True
2020 183 -30191.0 9.0 True
2020 184 -30319.0 22.0 True
2020 185 -31858.1 2.6 True
2020 186 -31715.0 21.0 True
2020 187 -33029.0 22.0 True
2020 188 -32371.3 2.7 True
2020 189 -33582.0 20.0 True
2020 190 -32834.0 3.0 True
2020 191 -33798.0 5.0 True
2020 192 -32772.0 16.0 True
2020 193 -33405.0 9.0 True
2020 194 -32211.9 2.1 True
2020 195 -32567.1 1.1 True
2020 196 -31138.7 3.0 True
2020 197 -31139.8 0.5 True
2020 198 -29580.8 0.5 True
2020 199 -29093.8 0.5 True
2020 200 -27240.0 27.0 True
2020 201 -26401.0 3.0 True
2020 202 -24353.0 23.0 True
2020 203 -23143.0 3.0 True
2020 204 -20390.0 200.0 False
2020 205 -18570.0 200.0 False
2020 206 -14190.0 300.0 False
2020 207 -10640.0 300.0 False
2020 208 -5910.0 300.0 False
2020 209 -2230.0 400.0 False
2020 210 2680.0 400.0 False
```

## Contributing

If you have ideas for additional functionality or find bugs please create an [issue](https://github.com/php1ic/nuclearmasses/issues) or better yet a [pull request](https://github.com/php1ic/nuclearmasses/pulls).

## Known issues
- The half life from the NUBASE data is stored as the individual elements, a column with the value in seconds would be useful
```python
>>> df[(df['A'] == 14) & (df['Symbol'] == 'C')][['HalfLifeValue', 'HalfLifeUnit', 'HalfLifeError']]
HalfLifeValue HalfLifeUnit HalfLifeError
TableYear
1983 NaN <NA> NaN
1993 NaN <NA> NaN
1995 5.73 ky 0.04
2003 5.70 ky 0.03
2012 5.70 ky 0.03
2016 5.70 ky 0.03
2020 5.70 ky 0.03
```
- The decay mode field from the NUBASE data is stored 'as-is' from the file.
It looks like it can be split on the ';' character for isotopes where there is more than one mode.
A dictionary of {decay mode: fraction} may be the best way to store all of this information.
- Information from anything other than the ground state of an isotope is ignored when parsing the NUABSE file.
The selection of what is and what is not included appears random to me which is why I simply ignored for the moment.
192 changes: 142 additions & 50 deletions nuclearmasses/ame_mass_file.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,148 @@
"""Storage for variable line positions."""
from nuclearmasses.parse import Parse
from nuclearmasses.element_converter import ElementConverter


class AMEMassFile(Parse):
class AMEMassFile(ElementConverter):
"""Easy access to where the variables are in the AME mass file."""

def __init__(self, year: int):
"""Setup up the values."""
super().__init__()
if year < 2020:
self.HEADER = 39
self.FOOTER = None
self.START_A = 16
self.END_A = 19
self.START_Z = 11
self.END_Z = 14
self.START_ME = 29
self.END_ME = 41
self.START_DME = 42
self.END_DME = 53
self.START_BE_PER_A = 54
self.END_BE_PER_A = 64
self.START_DBE_PER_A = 65
self.END_DBE_PER_A = 72
self.START_BETA_DECAY_ENERGY = 76
self.END_BETA_DECAY_ENERGY = 86
self.START_DBETA_DECAY_ENERGY = 87
self.END_DBETA_DECAY_ENERGY = 95
self.START_MICRO_U = 100
self.END_MICRO_U = 112
self.START_MICRO_DU = 113
self.END_MICRO_DU = 125
else:
self.HEADER = 36
self.FOOTER = None
self.START_A = 16
self.END_A = 19
self.START_Z = 11
self.END_Z = 14
self.START_ME = 29
self.END_ME = 42
self.START_DME = 43
self.END_DME = 53
self.START_BE_PER_A = 56
self.END_BE_PER_A = 66
self.START_DBE_PER_A = 69
self.END_DBE_PER_A = 77
self.START_BETA_DECAY_ENERGY = 82
self.END_BETA_DECAY_ENERGY = 93
self.START_DBETA_DECAY_ENERGY = 95
self.END_DBETA_DECAY_ENERGY = 104
self.START_MICRO_U = 110
self.END_MICRO_U = 120
self.START_MICRO_DU = 124
self.END_MICRO_DU = 135
match year:
case 1983:
self.HEADER = 35
self.FOOTER = 0
self.START_Z = 11
self.END_Z = 14
self.START_A = 16
self.END_A = 19
self.START_ME = 29
self.END_ME = 39
self.START_DME = 41
self.END_DME = 48
self.START_BE_PER_A = 49
self.END_BE_PER_A = 59
self.START_DBE_PER_A = 61
self.END_DBE_PER_A = 68
self.START_BETA_DECAY_ENERGY = 76
self.END_BETA_DECAY_ENERGY = 85
self.START_DBETA_DECAY_ENERGY = 87
self.END_DBETA_DECAY_ENERGY = 94
self.START_AM = 97
self.END_AM = 99
self.START_MICRO_U = 100
self.END_MICRO_U = 110
self.START_MICRO_DU = 113
self.END_MICRO_DU = 120
case 1993:
self.HEADER = 40
self.FOOTER = 0
self.START_Z = 11
self.END_Z = 14
self.START_A = 16
self.END_A = 19
self.START_ME = 29
self.END_ME = 39
self.START_DME = 41
self.END_DME = 48
self.START_BE_PER_A = 49
self.END_BE_PER_A = 59
self.START_DBE_PER_A = 61
self.END_DBE_PER_A = 68
self.START_BETA_DECAY_ENERGY = 76
self.END_BETA_DECAY_ENERGY = 85
self.START_DBETA_DECAY_ENERGY = 87
self.END_DBETA_DECAY_ENERGY = 94
self.START_AM = 97
self.END_AM = 99
self.START_MICRO_U = 100
self.END_MICRO_U = 110
self.START_MICRO_DU = 112
self.END_MICRO_DU = 120
case 1995:
self.HEADER = 39
self.FOOTER = 0
self.START_Z = 11
self.END_Z = 14
self.START_A = 16
self.END_A = 19
self.START_ME = 29
self.END_ME = 39
self.START_DME = 41
self.END_DME = 48
self.START_BE_PER_A = 49
self.END_BE_PER_A = 59
self.START_DBE_PER_A = 61
self.END_DBE_PER_A = 68
self.START_BETA_DECAY_ENERGY = 76
self.END_BETA_DECAY_ENERGY = 85
self.START_DBETA_DECAY_ENERGY = 87
self.END_DBETA_DECAY_ENERGY = 94
self.START_AM = 97
self.END_AM = 99
self.START_MICRO_U = 100
self.END_MICRO_U = 110
self.START_MICRO_DU = 112
self.END_MICRO_DU = 120
case 2020:
self.HEADER = 36
self.FOOTER = 0
self.START_Z = 11
self.END_Z = 14
self.START_A = 16
self.END_A = 19
self.START_ME = 29
self.END_ME = 42
self.START_DME = 43
self.END_DME = 53
self.START_BE_PER_A = 56
self.END_BE_PER_A = 66
self.START_DBE_PER_A = 69
self.END_DBE_PER_A = 77
self.START_BETA_DECAY_ENERGY = 82
self.END_BETA_DECAY_ENERGY = 93
self.START_DBETA_DECAY_ENERGY = 95
self.END_DBETA_DECAY_ENERGY = 104
self.START_AM = 106
self.END_AM = 109
self.START_MICRO_U = 110
self.END_MICRO_U = 120
self.START_MICRO_DU = 124
self.END_MICRO_DU = 135
case _:
self.HEADER = 39
self.FOOTER = 0
self.START_Z = 11
self.END_Z = 14
self.START_A = 16
self.END_A = 19
self.START_ME = 29
self.END_ME = 41
self.START_DME = 42
self.END_DME = 53
self.START_BE_PER_A = 54
self.END_BE_PER_A = 64
self.START_DBE_PER_A = 65
self.END_DBE_PER_A = 72
self.START_BETA_DECAY_ENERGY = 76
self.END_BETA_DECAY_ENERGY = 86
self.START_DBETA_DECAY_ENERGY = 87
self.END_DBETA_DECAY_ENERGY = 95
self.START_AM = 96
self.END_AM = 99
self.START_MICRO_U = 100
self.END_MICRO_U = 112
self.START_MICRO_DU = 113
self.END_MICRO_DU = 120

self.column_limits = [
(self.START_Z, self.END_Z),
(self.START_A, self.END_A),
(self.START_ME, self.END_ME),
(self.START_DME, self.END_DME),
(self.START_BE_PER_A, self.END_BE_PER_A),
(self.START_DBE_PER_A, self.END_DBE_PER_A),
(self.START_BETA_DECAY_ENERGY, self.END_BETA_DECAY_ENERGY),
(self.START_DBETA_DECAY_ENERGY, self.END_DBETA_DECAY_ENERGY),
(self.START_AM, self.END_AM),
(self.START_MICRO_U, self.END_MICRO_U),
(self.START_MICRO_DU, self.END_MICRO_DU),
]
Loading