From 3c99287c511be8094b6e3c2ee840e521dc96a1a7 Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 7 Jul 2023 14:30:25 -0400 Subject: [PATCH 01/12] Use AME2020 for neutron mass --- periodictable/constants.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/periodictable/constants.py b/periodictable/constants.py index 9e83710..5eb3088 100644 --- a/periodictable/constants.py +++ b/periodictable/constants.py @@ -15,12 +15,16 @@ #: electron radius r_e (m) electron_radius = 2.8179402894e-15 #(58) m -# From NIST Reference on Constants, Units, and Uncertainty +# [CODATA] From NIST Reference on Constants, Units, and Uncertainty # http://physics.nist.gov/cuu/index.html -# neutron mass = 1.008 664 915 97(43) u -# atomic mass constant m_u = 1.660 538 782(83) x 10-27 kg +# [AME2020] "The Ame2020 atomic mass evaluation (II)" +# by M.Wang, W.J.Huang, F.G.Kondev, G.Audi and S.Naimi +# Chinese Physics C45, 030003, March 2021. #: neutron mass (u) -neutron_mass = 1.00866491597 #(43) u +neutron_mass = 1.00866491590 #(47) u [AME 2020] +neutron_mass_unc = 0.00000000047 +#neutron_mass = 1.00866491597 #(43) u [CODATA 2010?] +#neutron_mass = 1.00866491595 #(49) u [CODATA 2018] #: atomic mass constant (kg / u) atomic_mass_constant = 1.660538782e-27 #(83) kg / u #: electron mass (u) From b653710b6bf23ea07a96229b5fb034ee6b12e9a3 Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 7 Jul 2023 14:30:55 -0400 Subject: [PATCH 02/12] Use IUPAC CIAAW tables for abundance and atomic weight --- doc/sphinx/guide/data_sources.rst | 7 +- periodictable/mass.py | 736 +++++++++++++++++++++++++++--- 2 files changed, 687 insertions(+), 56 deletions(-) diff --git a/doc/sphinx/guide/data_sources.rst b/doc/sphinx/guide/data_sources.rst index df5b232..d15e1e6 100644 --- a/doc/sphinx/guide/data_sources.rst +++ b/doc/sphinx/guide/data_sources.rst @@ -7,8 +7,11 @@ Data Sources Physical constants `NIST Physics Laboratory - Constants, units and uncertainty `_ -Atomic and isotope mass - `NIST Physics Laboratory - Atomic weights and isotope composition `_ +Isotope mass + `IAEA Atomic Mass Data Center AME2020 `_ + +Atomic weight and isotope abundance + `IUPAC commission on isotope abundances and atomic weights `_ Atomic density *ILL Neutron Data Booklet* diff --git a/periodictable/mass.py b/periodictable/mass.py index 8518a56..fb8d3d5 100644 --- a/periodictable/mass.py +++ b/periodictable/mass.py @@ -3,12 +3,12 @@ # Author: Paul Kienzle u""" -Adds average mass for the elements: +Provides average mass for the elements: * mass, mass_units (u) The molar mass averaged over natural isotope abundance. -Adds mass and abundance information for isotopes: +Provides mass and abundance information for isotopes: * mass, mass_units (u) The molar mass of the individual isotope. @@ -16,55 +16,78 @@ * abundance, abundance_units (%) Natural abundance for the isotope. -Atomic Weights and Isotopic Composition [#Coursey]_. +The atomic mass data for the isotopes and for the neutron were published +by Wang [#Wang]_ in the AME 2020 atomic mass evaluation (II). -The atomic weights are available for elements 1 through 118 and -isotopic compositions or abundances are given when appropriate. The atomic -weights data were published by Wang [#Wang]_ in The AME 2020 atomic mass -evaluation (II). Hashes `#` after values indicate vlaues which are not solely -derived from experiment, see the paper for details. Trailing zeros do not -necessarily indicate uncertainties quoted in the reference. Tables, graphs and -references, and the isotopic compositions data were published by Rosman -[#Rosman]_ and Taylor [#Taylor]_ in Isotopic Compositions of the Elements 1997. -The relative atomic masses of the isotopes data were published by Audi [#Audi]_ -and Wapstra [#Wapstra]_ in the 1995 Update To The Atomic Mass Evaluation. +Natural abundance mass and isotope fractions come from the IUPAC commission +on isotopic abundances and atomic weights (CIAAW) [#CIAAW]_. This is an +ill-defined problem since there is natural fractionation of the isotopes, +giving different masses and ratios from different samples. The current +recommended table therefore gives ranges of values for the natural mass +and isotope abundance rather than a single value with an uncertainty. -This data has been compiled from the above sources for the user's convenience -and does not represent a critical evaluation by the NIST Physics Laboratory. -http://physics.nist.gov/PhysRefData/Compositions/ +For periodictable, fractionation ranges for masses were replaced with abridged +standard atomic weights as given in Prohaska [#Prohaska]. For the abundance +ratios the center value of the range was chosen. A few elements had to be +adjusted slightly so that they would sum to 100%. -Neutron mass from NIST Reference on Constants, Units, and Uncertainty -http://physics.nist.gov/cuu/index.html +The values for Ar and N were set to the values present in the atmosphere +and U was set to the values in a Namibian ore per the recommendations +in Meija (2016). -.. [#Coursey] Coursey. J. S., Schwab. D. J., and Dragoset. R. A., NIST, - Physics Laboratory, Office of Electronic Commerce in Scientific - and Engineering Data. -.. [#Coplen] Coplen. T. B. : U.S. Geological Survey, Reston, Virginia, USA. -.. [#Rosman] Rosman. K. J. R. : Department of Applied Physics, Curtin University - of Technology, Australia. -.. [#Taylor] Taylor. P. D. P. : Institute for Reference Materials and - Measurements, European Commission, Belgium. -.. [#Audi] Audi. G. : Centre de Spectrométrie Nucléaire et de Spectrométrie - de Masse, Orsay Campus, France. -.. [#Wang] Wang. M., Huang. W. J., Kondev. F. G., Audi. G., Naimi. S., - Institute of Modern Physics, Chinese Academy of Sciences, -.. [#Wapstra] Wapstra. A. H. : National Institute of Nuclear Physics - and High-Energy Physics, Amsterdam, The Netherlands. -""" +The values for Pb in the CIAAW table are too broad to be usable. For example, +206-Pb varies from 0.02 to 0.87 in monazite samples (Zhu 2020) [#Zhu]. Rather +than return NaN for composition we replace the ranges with representative +atomic abundance values in Meija (2016). See the CIAAW page on +`lead `_ for details. -from .core import Element, Isotope -from .constants import neutron_mass +.. [#CIAAW] CIAAW. Isotopic compositions of the elements 2021. + Available online at www.ciaaw.org. +.. [#Wang] Meng Wang et al. (2021) Chinese Phys. C 45 030003 + DOI:10.1088/1674-1137/abddaf + From https://www-nds.iaea.org/amdc/ame2020/massround.mas20.txt (2023-07-06) +.. [#Meija] J. Meija et al. (2016) + Isotopic compositions of the elements 2013 + Pure and Applied Chemistry 88, 293-306. + From https://www.ciaaw.org/isotopic-abundances.htm (2023-07-06) +.. [#Prohaska] T. Prohaska, et al. (2022) + Standard atomic weights of the elements 2021. + Pure Appl. Chem. 94. DOI:10.1515/pac-2019-0603 + From https://www.ciaaw.org/atomic-weights.htm (2023-07-06) +.. [*Zhu] Zhu, X., Benefield, J., Coplen, T., Gao, Z. & Holden, N. (2021). + Variation of lead isotopic composition and atomic weight in terrestrial + materials (IUPAC Technical Report). Pure and Applied Chemistry, 93(1), 155-166. + https://doi.org/10.1515/pac-2018-0916 +""" +from .core import Element, Isotope, default_table +from .constants import neutron_mass, neutron_mass_unc +def _parse_mass(s): + if s == "": # missing + return 0, 0 + # Parse [nominal] or [low,high] + if s.startswith('['): + s = s[1:-1] + parts = s.split(',') + if len(parts) > 1: + low, high = float(parts[0]), float(parts[1]) + return (high+low)/2, (high-low)/2 + else: + return float(parts[0]), 0 + # Parse value(unc) with perhaps '#' at the end + parts = s.split('(') + if len(parts) > 1: + # Split the value and uncertainty. + value, unc = parts[0], parts[1].split(')')[0] + # Count digits after the decimal for value and produce + # 0.00...0{unc} with the right number of zeros. + if not '.' in unc: + zeros = len(value.split('.')[1]) - len(unc) + unc = "0." + ("0"*zeros) + unc + return float(value), float(unc) + # Plain value with no uncertainty + return float(s), 0 -def _parse_mass(str): - idx = str.find('(') - if idx > 0: # value(uncertainty) - return float(str[:idx]) - if str.startswith('['): # [nominal] - return int(str[1:-1]) - if str == "": # missing - return 0 - return float(str) def mass(isotope): """ @@ -110,25 +133,630 @@ def init(table, reload=False): Element.mass_units = "u" Element.abundance_units = "%" - for line in massdata.split('\n'): + # Parse isotope mass table where each line looks like: + # z-el-iso,isotope mass(unc)#?,abundance(unc),element mass(unc) + # The abundance and element masses will be superceded below + for line in isotope_mass.split('\n'): isotope, m, p, avg = line.split(',') - el, sym, iso = isotope.split('-') - el = table[int(el)] + z, sym, iso = isotope.split('-') + el = table[int(z)] assert el.symbol == sym, \ "Symbol %s does not match %s"%(sym, el.symbol) iso = el.add_isotope(int(iso)) - el._mass = _parse_mass(avg) - iso._mass = _parse_mass(m) - iso._abundance = _parse_mass(p) + el._mass, el._mass_unc = _parse_mass(avg) + iso._mass, iso._mass_unc = _parse_mass(m) + iso._abundance, iso._abundance_unc = _parse_mass(p) # A single neutron is an isotope of element 0 el = table[0] - el._mass = neutron_mass + el._mass, el._mass_unc = neutron_mass, neutron_mass_unc iso = el.add_isotope(1) - iso._mass = neutron_mass - iso._abundance = 100 + iso._mass, iso._mass_unc = neutron_mass, neutron_mass_unc + iso._abundance, iso._abundance_unc = 100, 0 + + # Parse element mass table where each line looks like: + # z El element mass(unc)|[low,high]|- note note ... + for line in element_mass.split('\n'): + z, symbol, name, value = line.split()[:4] + #print(z, symbol, name, value) + el = table[int(z)] + if value != '-': + #v, dv = _parse_mass(value) + #delta = abs(v-el._mass)/el._mass*100 + #from uncertainties import ufloat as U + #if delta > 0.01: + # print(f"{el.number}-{el.symbol} mass changed by {delta:.2f}% to {U(v,dv):fS} from {U(el._mass,el._mass_unc):fS}") + el._mass, el._mass_unc = _parse_mass(value) + + #Li_ratio = table.Li[7]._abundance/table.Li[6]._abundance + + # Parse isotope abundance table where lines look like: + # z El element\n iso mass(unc)|[low,high] note ... + # Note: tables modified for Pb, Ar, and N to use 2013 values + z = 0 + value = {} + for line in isotope_abundance.split('\n'): + #print(line) + # New element + if line[0] not in ' \t': + if z: # not the start + #print(f"update z {z}-{table[z]}", value) + el = table[z] + # Find total so we can normalize fractions to sum to one. + # This affects O, Mg, S, Hf by amounts less than the uncertainty. + total = sum(v[0] for k, v in value.items()) + #if abs(total - 1) > 1e-10: print("total deviation for %s is %g"%(el, total-1)) + for z, pair in value.items(): + iso = el[z] + #from uncertainties import ufloat as U + #v, dv = 100*pair[0]/total, 100*pair[1]/total + #delta = abs(v-iso._abundance) + #if delta >= 0.1 and v>1: + # print(f"{el.number}-{el.symbol}-{z} abundance changed by {delta:.2f}% to {U(v,dv):fS} from {U(iso._abundance,iso._abundance_unc):fS}") + + iso._abundance = 100*pair[0]/total + iso._abundance_unc = 100*pair[1]/total + z = int(line.strip().split()[0]) + value = {} + #print(f"new z {z}-{table[z]}")# from <{line}>") + else: + #print(line) + parts = line.strip().split() + #print(parts) + value[int(parts[0])] = _parse_mass(parts[1]) + + #new_Li_ratio = table.Li[7]._abundance/table.Li[6]._abundance + #print(f"Li6:Li7 ratio changed from {Li_ratio:.1f} to {new_Li_ratio:.1f}") + + +def print_natural_mass(table=None): + from uncertainties import ufloat as U + table = default_table(table) + for el in table: + iso_mass = [ + U(iso.abundance, iso._abundance_unc)/100*U(iso.mass, iso._mass_unc) + for iso in el if iso.abundance>0] + if iso_mass: + el_mass = U(el.mass, el._mass_unc) + iso_sum = sum(iso_mass) + delta = el_mass - iso_sum + # python 3.6 and above only + if abs(delta.n) > 1e-3 or delta.s/iso_sum.n > 0.01: + print(f"{el.number}-{el}: {el_mass:fS}, sum: {iso_sum:fS}, Δ={delta:fS}") + #print(f"{el.number}-{el}: {delta:fS}") + #print(f"{el.number}-{el}: {el_mass:fS}, sum: {iso_sum:fS}, Δ=") + #print(f"{el.number}-{el}: {delta:fS}") + #print("%d-%s: %s (from sum: %s)"%(el.number, el, str(el_mass), str(iso_sum))) + +def print_abundance(table=None): + table = default_table(table) + for el in table: + abundance = ["%8s %g"%(iso, iso.abundance/100) for iso in el if iso.abundance>0] + if abundance: + print("\n".join(abundance)) + print() + +def check_abundance(table=None): + table = default_table(table) + for el in table: + abundance = [iso.abundance for iso in el if iso.abundance>0] + if abundance: + assert abs(sum(abundance) - 100.0) < 1e-12,\ + "Inconsistent abundance for %d-%s: %g"%(el.number,el,sum(abundance)) + + + + +# Table of masses. +# g Geological and biological materials are known in which the element has an +# isotopic composition outside the limits for normal material. The difference +# between the atomic weight of the element in such materials and that given in +# the table may exceed the stated uncertainty. +# m Modified isotopic compositions may be found in commercially available +# material because the material has been subjected to some undisclosed +# or inadvertent isotopic fractionation. Substantial deviations in atomic +# weight of the element from that given in the table can occur. +# r Range in isotopic composition of normal terrestrial material prevents +# a more precise standard atomic weight being given; the tabulated value +# and uncertainty should be applicable to normal material. +# +# Fractionation ranges have been replaced with the abridged standard weights +# as giving in Prohaska(2022). +# +# CIAAW. Isotopic compositions of the elements 2021. Available online at www.ciaaw.org. +# +# https://www.ciaaw.org/atomic-weights.htm (2023-07-06) + +#Z Symbol Element Standard Atomic Weight Notes +element_mass = """\ +1 H hydrogen 1.0080(2) [1.00784,1.00811] m +2 He helium 4.002602(2) g r +3 Li lithium 6.94(6) [6.938,6.997] m +4 Be beryllium 9.0121831(5) +5 B boron 10.81(2) [10.806,10.821] m +6 C carbon 12.011(2) [12.0096,12.0116] +7 N nitrogen 14.007(1) [14.00643,14.00728] m +8 O oxygen 15.999(1) [15.99903,15.99977] m +9 F fluorine 18.998403162(5) +10 Ne neon 20.1797(6) g m +11 Na sodium 22.98976928(2) +12 Mg magnesium 24.305(2) [24.304,24.307] +13 Al aluminium 26.9815384(3) +14 Si silicon 28.085(1) [28.084,28.086] +15 P phosphorus 30.973761998(5) +16 S sulfur 32.06(2) [32.059,32.076] +17 Cl chlorine 35.45(1) [35.446,35.457] m +18 Ar argon 39.95(16) [39.792,39.963] +19 K potassium 39.0983(1) +20 Ca calcium 40.078(4) g +21 Sc scandium 44.955907(4) +22 Ti titanium 47.867(1) +23 V vanadium 50.9415(1) +24 Cr chromium 51.9961(6) +25 Mn manganese 54.938043(2) +26 Fe iron 55.845(2) +27 Co cobalt 58.933194(3) +28 Ni nickel 58.6934(4) r +29 Cu copper 63.546(3) r +30 Zn zinc 65.38(2) r +31 Ga gallium 69.723(1) +32 Ge germanium 72.630(8) +33 As arsenic 74.921595(6) +34 Se selenium 78.971(8) r +35 Br bromine 79.904(3) [79.901,79.907] +36 Kr krypton 83.798(2) g m +37 Rb rubidium 85.4678(3) g +38 Sr strontium 87.62(1) g r +39 Y yttrium 88.905838(2) +40 Zr zirconium 91.224(2) g +41 Nb niobium 92.90637(1) +42 Mo molybdenum 95.95(1) g +44 Ru ruthenium 101.07(2) g +45 Rh rhodium 102.90549(2) +46 Pd palladium 106.42(1) g +47 Ag silver 107.8682(2) g +48 Cd cadmium 112.414(4) g +49 In indium 114.818(1) +50 Sn tin 118.710(7) g +51 Sb antimony 121.760(1) g +52 Te tellurium 127.60(3) g +53 I iodine 126.90447(3) +54 Xe xenon 131.293(6) g m +55 Cs caesium 132.90545196(6) +56 Ba barium 137.327(7) +57 La lanthanum 138.90547(7) g +58 Ce cerium 140.116(1) g +59 Pr praseodymium 140.90766(1) +60 Nd neodymium 144.242(3) g +62 Sm samarium 150.36(2) g +63 Eu europium 151.964(1) g +64 Gd gadolinium 157.25(3) g +65 Tb terbium 158.925354(7) +66 Dy dysprosium 162.500(1) g +67 Ho holmium 164.930329(5) +68 Er erbium 167.259(3) g +69 Tm thulium 168.934219(5) +70 Yb ytterbium 173.045(10) g +71 Lu lutetium 174.9668(1) g +72 Hf hafnium 178.486(6) g +73 Ta tantalum 180.94788(2) +74 W tungsten 183.84(1) +75 Re rhenium 186.207(1) +76 Os osmium 190.23(3) g +77 Ir iridium 192.217(2) +78 Pt platinum 195.084(9) +79 Au gold 196.966570(4) +80 Hg mercury 200.592(3) +81 Tl thallium 204.38(1) [204.382,204.385] +82 Pb lead 207.2(1.1) [206.14,207.94] +83 Bi bismuth 208.98040(1) +90 Th thorium 232.0377(4) g +91 Pa protactinium 231.03588(1) +92 U uranium 238.02891(3) g m\ +""" + + +# From https://www.ciaaw.org/isotopic-abundances.htm (2023-07-06) +# CIAAW. Isotopic compositions of the elements 2021. Available online at www.ciaaw.org. + +# Nominal values for lead are from Meija (2013) since the natural variation +# given in the 2021 tables are completely unusable. Maybe better to use NaN? +# Similarly nitrogen and argon were chosen to match air rather than average +# terrestrial abundance. +# All other values use midpoint of the range, scaled so that the sum of the +# isotopes equals 100%. + +#Z El element +# isotope Representative isotopic composition Notes +isotope_abundance = """\ +1 H hydrogen + 1 [0.99972,0.99999] m + 2 [0.00001,0.00028] +2 He helium + 3 0.000002(2) g r + 4 0.999998(2) +3 Li lithium + 6 [0.019,0.078] m + 7 [0.922,0.981] +4 Be beryllium + 9 1 +5 B boron + 10 [0.189,0.204] m + 11 [0.796,0.811] +6 C carbon + 12 [0.9884,0.9904] + 13 [0.0096,0.0116] +7 N nitrogen + 14 0.996337(4) [0.99578,0.99663] + 15 0.003663(4) [0.00337,0.00422] +8 O oxygen + 16 [0.99738,0.99776] + 17 [0.000367,0.000400] + 18 [0.00187,0.00222] +9 F fluorine + 19 1 +10 Ne neon + 20 0.9048(3) g m + 21 0.0027(1) + 22 0.0925(3) +11 Na sodium + 23 1 +12 Mg magnesium + 24 [0.7888,0.7905] + 25 [0.09988,0.10034] + 26 [0.1096,0.1109] +13 Al aluminium + 27 1 +14 Si silicon + 28 [0.92191,0.92318] + 29 [0.04645,0.04699] + 30 [0.03037,0.03110] +15 P phosphorus + 31 1 +16 S sulfur + 32 [0.9441,0.9529] + 33 [0.00729,0.00797] + 34 [0.0396,0.0477] + 36 [0.000129,0.000187] +17 Cl chlorine + 35 [0.755,0.761] m + 37 [0.239,0.245] +18 Ar argon + 36 0.0033361(35) [0.0000,0.0207] g r + 38 0.0006289(12) [0.000,0.043] + 40 0.9960350(42) [0.936,1.000] +19 K potassium + 39 0.932581(44) + 40 0.000117(1) + 41 0.067302(44) +20 Ca calcium + 40 0.96941(156) g + 42 0.00647(23) + 43 0.00135(10) + 44 0.02086(110) + 46 0.00004(3) + 48 0.00187(21) +21 Sc scandium + 45 1 +22 Ti titanium + 46 0.0825(3) + 47 0.0744(2) + 48 0.7372(3) + 49 0.0541(2) + 50 0.0518(2) +23 V vanadium + 50 0.00250(10) + 51 0.99750(10) +24 Cr chromium + 50 0.04345(13) + 52 0.83789(18) + 53 0.09501(17) + 54 0.02365(7) +25 Mn manganese + 55 1 +26 Fe iron + 54 0.05845(105) + 56 0.91754(106) + 57 0.02119(29) + 58 0.00282(12) +27 Co cobalt + 59 1 +28 Ni nickel + 58 0.680769(190) r + 60 0.262231(150) + 61 0.011399(13) + 62 0.036345(40) + 64 0.009256(19) +29 Cu copper + 63 0.6915(15) r + 65 0.3085(15) +30 Zn zinc + 64 0.4917(75) r + 66 0.2773(98) + 67 0.0404(16) + 68 0.1845(63) + 70 0.0061(10) +31 Ga gallium + 69 0.60108(50) + 71 0.39892(50) +32 Ge germanium + 70 0.2052(19) + 72 0.2745(15) + 73 0.0776(8) + 74 0.3652(12) + 76 0.0775(12) +33 As arsenic + 75 1 +34 Se selenium + 74 0.0086(3) r + 76 0.0923(7) + 77 0.0760(7) + 78 0.2369(22) + 80 0.4980(36) + 82 0.0882(15) +35 Br bromine + 79 [0.505,0.508] + 81 [0.492,0.495] +36 Kr krypton + 78 0.00355(3) g m + 80 0.02286(10) + 82 0.11593(31) + 83 0.11500(19) + 84 0.56987(15) + 86 0.17279(41) +37 Rb rubidium + 85 0.7217(2) g + 87 0.2783(2) +38 Sr strontium + 84 0.0056(2) g r + 86 0.0986(20) + 87 0.0700(20) + 88 0.8258(35) +39 Y yttrium + 89 1 +40 Zr zirconium + 90 0.5145(4) g + 91 0.1122(5) + 92 0.1715(3) + 94 0.1738(4) + 96 0.0280(2) +41 Nb niobium + 93 1 +42 Mo molybdenum + 92 0.14649(106) g + 94 0.09187(33) + 95 0.15873(30) + 96 0.16673(8) + 97 0.09582(15) + 98 0.24292(80) + 100 0.09744(65) +44 Ru ruthenium + 96 0.0554(14) g + 98 0.0187(3) + 99 0.1276(14) + 100 0.1260(7) + 101 0.1706(2) + 102 0.3155(14) + 104 0.1862(27) +45 Rh rhodium + 103 1 +46 Pd palladium + 102 0.0102(1) g + 104 0.1114(8) + 105 0.2233(8) + 106 0.2733(3) + 108 0.2646(9) + 110 0.1172(9) +47 Ag silver + 107 0.51839(8) g + 109 0.48161(8) +48 Cd cadmium + 106 0.01245(22) g + 108 0.00888(11) + 110 0.12470(61) + 111 0.12795(12) + 112 0.24109(7) + 113 0.12227(7) + 114 0.28754(81) + 116 0.07512(54) +49 In indium + 113 0.04281(52) + 115 0.95719(52) +50 Sn tin + 112 0.0097(1) g + 114 0.0066(1) + 115 0.0034(1) + 116 0.1454(9) + 117 0.0768(7) + 118 0.2422(9) + 119 0.0859(4) + 120 0.3258(9) + 122 0.0463(3) + 124 0.0579(5) +51 Sb antimony + 121 0.5721(5) g + 123 0.4279(5) +52 Te tellurium + 120 0.0009(1) g + 122 0.0255(12) + 123 0.0089(3) + 124 0.0474(14) + 125 0.0707(15) + 126 0.1884(25) + 128 0.3174(8) + 130 0.3408(62) +53 I iodine + 127 1 +54 Xe xenon + 124 0.00095(5) g m + 126 0.00089(3) + 128 0.01910(13) + 129 0.26401(138) + 130 0.04071(22) + 131 0.21232(51) + 132 0.26909(55) + 134 0.10436(35) + 136 0.08857(72) +55 Cs caesium + 133 1 +56 Ba barium + 130 0.0011(1) + 132 0.0010(1) + 134 0.0242(15) + 135 0.0659(10) + 136 0.0785(24) + 137 0.1123(23) + 138 0.7170(29) +57 La lanthanum + 138 0.0008881(71) g + 139 0.9991119(71) +58 Ce cerium + 136 0.00185(2) g + 138 0.00251(2) + 140 0.88450(51) + 142 0.11114(51) +59 Pr praseodymium + 141 1 +60 Nd neodymium + 142 0.27152(40) g + 143 0.12174(26) + 144 0.23798(19) + 145 0.08293(12) + 146 0.17189(32) + 148 0.05756(21) + 150 0.05638(28) +62 Sm samarium + 144 0.0308(4) g + 147 0.1500(14) + 148 0.1125(9) + 149 0.1382(10) + 150 0.0737(9) + 152 0.2674(9) + 154 0.2274(14) +63 Eu europium + 151 0.4781(6) g + 153 0.5219(6) +64 Gd gadolinium + 152 0.0020(3) g + 154 0.0218(2) + 155 0.1480(9) + 156 0.2047(3) + 157 0.1565(4) + 158 0.2484(8) + 160 0.2186(3) +65 Tb terbium + 159 1 +66 Dy dysprosium + 156 0.00056(3) g + 158 0.00095(3) + 160 0.02329(18) + 161 0.18889(42) + 162 0.25475(36) + 163 0.24896(42) + 164 0.28260(54) +67 Ho holmium + 165 1 +68 Er erbium + 162 0.00139(5) g + 164 0.01601(3) + 166 0.33503(36) + 167 0.22869(9) + 168 0.26978(18) + 170 0.14910(36) +69 Tm thulium + 169 1 +70 Yb ytterbium + 168 0.00126(1) g + 170 0.03023(2) + 171 0.14216(7) + 172 0.21754(10) + 173 0.16098(9) + 174 0.31896(26) + 176 0.12887(30) +71 Lu lutetium + 175 0.97401(13) g + 176 0.02599(13) +72 Hf hafnium + 174 0.00161(2) g + 176 0.0524(14) + 177 0.1858(9) + 178 0.2728(6) + 179 0.1363(3) + 180 0.3512(16) +73 Ta tantalum + 180 0.0001176(23) + 181 0.9998824(23) +74 W tungsten + 180 0.0012(1) + 182 0.2650(16) + 183 0.1431(4) + 184 0.3064(2) + 186 0.2843(19) +75 Re rhenium + 185 0.3740(5) + 187 0.6260(5) +76 Os osmium + 184 0.0002(2) g + 186 0.0159(64) + 187 0.0196(17) + 188 0.1324(27) + 189 0.1615(23) + 190 0.2626(20) + 192 0.4078(32) +77 Ir iridium + 191 0.3723(9) + 193 0.6277(9) +78 Pt platinum + 190 0.00012(2) + 192 0.00782(24) + 194 0.32864(410) + 195 0.33775(240) + 196 0.25211(340) + 198 0.07356(130) +79 Au gold + 197 1 +80 Hg mercury + 196 0.0015(1) + 198 0.1004(3) + 199 0.1694(12) + 200 0.2314(9) + 201 0.1317(9) + 202 0.2974(13) + 204 0.0682(4) +81 Tl thallium + 203 [0.2944,0.2959] + 205 [0.7041,0.7056] +82 Pb lead + 204 0.014(6) [0.0000,0.0158] + 206 0.241(30) [0.0190,0.8673] + 207 0.221(50) [0.0035,0.2351] + 208 0.524(70) [0.0338,0.9775] +83 Bi bismuth + 209 1 +90 Th thorium + 230 0.0002(2) g + 232 0.9998(2) +91 Pa protactinium + 231 1 +92 U uranium + 234 0.000054(5) g m + 235 0.007204(6) + 238 0.992742(10)\ +""" + + +# Table of isotope masses from Wang(2021). The mass uncertainties have been rounded to one +# or two digits, but trailing zeros remain. Hashes `#` after mass(unc.) indicate +# values which are not solely derived from experiment, see the paper for details. +# Atomic weights and isotope ratios come from Coursey(?) downloaded c. 2010. +# These are ignored, and will be replaced by the IUPAC CIAAW values from 2021. +# Meng Wang et al. (2021) Chinese Phys. C 45 030003 +# DOI:10.1088/1674-1137/abddaf +# Coursey. J. S., Schwab. D. J., and Dragoset. R. A., NIST, +# Physics Laboratory, Office of Electronic Commerce in Scientific +# and Engineering Data. -massdata = """\ +isotope_mass = """\ 1-H-1,1.0078250319000(100),99.9885(70),1.00794(7) 1-H-2,2.0141017778400(200),0.0115(70),1.00794(7) 1-H-3,3.0160492813200(800),,1.00794(7) From 45b65e3d72ae2b20d34bebe5da762c1d645f1014 Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 7 Jul 2023 14:32:14 -0400 Subject: [PATCH 03/12] Start noting changes to mass tables --- README.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.rst b/README.rst index d7f699c..6d054b0 100644 --- a/README.rst +++ b/README.rst @@ -73,6 +73,18 @@ Known issues Change history ============== +1.7.0 2023-07-?? +---------------- + +Modified: + +* Move to IAEA AME2020 for isotope mass +* Move to IUPAC CIAAW for atomic weight and isotopic abundance +* Li-6:Li-7 ratio changed from 12.2 to 19.6 (delta = 2.7%) +* Isotope percentage changed by 0.1 to 0.5 for B, Zn, Ge, Se, Mo, Er, Yb, Pt, Hg +* Atomic weight changed by 0.04% for Zn, 0.02% for S and 0.01% for Li, Ge, Se, Mo + + 1.6.1 2022-05-18 ---------------- From 64de891f6af2a5e0bf6e64e2bab43d660f7fc0ae Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Tue, 22 Aug 2023 17:48:17 -0400 Subject: [PATCH 04/12] Move uncertainty parser to util so it can be used for other tables --- periodictable/mass.py | 40 +++++++---------------------------- periodictable/util.py | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/periodictable/mass.py b/periodictable/mass.py index fb8d3d5..64a1bab 100644 --- a/periodictable/mass.py +++ b/periodictable/mass.py @@ -61,33 +61,7 @@ """ from .core import Element, Isotope, default_table from .constants import neutron_mass, neutron_mass_unc - -def _parse_mass(s): - if s == "": # missing - return 0, 0 - # Parse [nominal] or [low,high] - if s.startswith('['): - s = s[1:-1] - parts = s.split(',') - if len(parts) > 1: - low, high = float(parts[0]), float(parts[1]) - return (high+low)/2, (high-low)/2 - else: - return float(parts[0]), 0 - # Parse value(unc) with perhaps '#' at the end - parts = s.split('(') - if len(parts) > 1: - # Split the value and uncertainty. - value, unc = parts[0], parts[1].split(')')[0] - # Count digits after the decimal for value and produce - # 0.00...0{unc} with the right number of zeros. - if not '.' in unc: - zeros = len(value.split('.')[1]) - len(unc) - unc = "0." + ("0"*zeros) + unc - return float(value), float(unc) - # Plain value with no uncertainty - return float(s), 0 - +from .util import parse_uncertainty def mass(isotope): """ @@ -143,9 +117,9 @@ def init(table, reload=False): assert el.symbol == sym, \ "Symbol %s does not match %s"%(sym, el.symbol) iso = el.add_isotope(int(iso)) - el._mass, el._mass_unc = _parse_mass(avg) - iso._mass, iso._mass_unc = _parse_mass(m) - iso._abundance, iso._abundance_unc = _parse_mass(p) + el._mass, el._mass_unc = parse_uncertainty(avg) + iso._mass, iso._mass_unc = parse_uncertainty(m) + iso._abundance, iso._abundance_unc = parse_uncertainty(p) # A single neutron is an isotope of element 0 el = table[0] @@ -161,12 +135,12 @@ def init(table, reload=False): #print(z, symbol, name, value) el = table[int(z)] if value != '-': - #v, dv = _parse_mass(value) + #v, dv = parse_uncertainty(value) #delta = abs(v-el._mass)/el._mass*100 #from uncertainties import ufloat as U #if delta > 0.01: # print(f"{el.number}-{el.symbol} mass changed by {delta:.2f}% to {U(v,dv):fS} from {U(el._mass,el._mass_unc):fS}") - el._mass, el._mass_unc = _parse_mass(value) + el._mass, el._mass_unc = parse_uncertainty(value) #Li_ratio = table.Li[7]._abundance/table.Li[6]._abundance @@ -203,7 +177,7 @@ def init(table, reload=False): #print(line) parts = line.strip().split() #print(parts) - value[int(parts[0])] = _parse_mass(parts[1]) + value[int(parts[0])] = parse_uncertainty(parts[1]) #new_Li_ratio = table.Li[7]._abundance/table.Li[6]._abundance #print(f"Li6:Li7 ratio changed from {Li_ratio:.1f} to {new_Li_ratio:.1f}") diff --git a/periodictable/util.py b/periodictable/util.py index f7917b1..2f9c25e 100644 --- a/periodictable/util.py +++ b/periodictable/util.py @@ -3,6 +3,55 @@ """ Helper functions """ +from math import sqrt + +def parse_uncertainty(s): + """ + Given a floating point value plus uncertainty return the pair (val, unc). + + Format is val, val(unc), [nominal] or [low,high]. + + The val(unc) form is like 23.0035(12), but also 23(1), 23.0(1.0), or + maybe even 23(1.0). This parser does not handle exponential notation + such as 1.032(4)E10 + + The nominal form has zero uncertainty, as does a bare value. + + The [low,high] form is assumed to be a rectangular distribution of 1-sigma + equivalent width (high-low)/sqrt(12). + + An empty string is returned as None,None rather than 0,inf. + """ + if s == "": # missing + # TODO: maybe 0 +/- inf ? + return None, None + + # Parse [nominal] or [low,high] + if s.startswith('['): + s = s[1:-1] + parts = s.split(',') + if len(parts) > 1: + low, high = float(parts[0]), float(parts[1]) + # Use equivalent 1-sigma width for a rectangular distribution + return (high+low)/2, (high-low)/sqrt(12) + else: + return float(parts[0]), 0 + + # Parse value(unc) with perhaps '#' at the end + parts = s.split('(') + if len(parts) > 1: + # Split the value and uncertainty. + value, unc = parts[0], parts[1].split(')')[0] + # Count digits after the decimal for value and produce + # 0.00...0{unc} with the right number of zeros. + # e.g., 23.0035(12) but not 23(1) or 23.0(1.0) or 23(1.0) + if '.' not in unc and '.' in value: + zeros = len(value.split('.')[1]) - len(unc) + unc = "0." + ("0"*zeros) + unc + return float(value), float(unc) + + # Plain value with no uncertainty + return float(s), 0 def cell_volume(a=None, b=None, c=None, alpha=None, beta=None, gamma=None): r""" From c7e55da685b50c8dfb41c7c354a38d57dd8233fa Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Tue, 22 Aug 2023 17:53:34 -0400 Subject: [PATCH 05/12] Fix typos in ATI tables: Zr[90].neutron.b_c changes from 6.9 to 6.0 --- README.rst | 4 +++- periodictable/nsf.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 6d054b0..9d38516 100644 --- a/README.rst +++ b/README.rst @@ -80,9 +80,11 @@ Modified: * Move to IAEA AME2020 for isotope mass * Move to IUPAC CIAAW for atomic weight and isotopic abundance -* Li-6:Li-7 ratio changed from 12.2 to 19.6 (delta = 2.7%) +* Li-6:Li-7 mass ratio changed from 12.2 to 19.6 (delta = 2.7%) * Isotope percentage changed by 0.1 to 0.5 for B, Zn, Ge, Se, Mo, Er, Yb, Pt, Hg * Atomic weight changed by 0.04% for Zn, 0.02% for S and 0.01% for Li, Ge, Se, Mo +* Zn-70 b_c changed from 6.9 to 6.0 (fixing a typo in the ATI tables) +* Fix typos in uncertainties for the ATI table (Zr-90, Te-124, Sm-147) 1.6.1 2022-05-18 diff --git a/periodictable/nsf.py b/periodictable/nsf.py index 8d1d01d..e9c5962 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -143,7 +143,7 @@ from .core import Element, Isotope, default_table from .constants import (avogadro_number, plancks_constant, electron_volt, neutron_mass, atomic_mass_constant) -from .util import require_keywords +from .util import require_keywords, parse_uncertainty __all__ = ['init', 'Neutron', 'neutron_energy', 'neutron_wavelength', @@ -303,7 +303,8 @@ class Neutron(object): * absorption (barn) Absorption cross section $\sigma_a$ at 1.798 |Ang|. Scale to your beam by dividing by periodictable.nsf.ABSORPTION_WAVELENGTH and multiplying - by your wavelength. + by your wavelength. This wavelength corresponds to a neutron velocity + of 2200 m/s and neutron energy of 25.3 meV. * b_c_complex (fm) Complex coherent scattering length derived from the tabulated @@ -1257,6 +1258,7 @@ def sld_plot(table=None): # The coherent and incoherent scattering cross-sections in barns. # absorption # The thermal absorption cross section in barns at 1.798 Angstroms/25.30 meV. +# 2200 m/s # # Numbers in parenthesis represents uncertainty. # Numbers followed by '*' are estimated. @@ -1365,7 +1367,7 @@ def sld_plot(table=None): 30-Zn-66,27.8,0,5.98(5),,,,4.48(8),0,4.48(8),0.62(6) 30-Zn-67,4.1,5/2,7.58(8),5.8(5),10.1(7),+/-,7.18(15),0.28(3),7.46(15),6.8(8) 30-Zn-68,18.6,0,6.04(3),,,,4.57(5),0,4.57(5),1.1(1) -30-Zn-70,0.62,0,6.9(1.0)*,,,,4.5(1.5),0,4.5(1.5),0.092(5) +30-Zn-70,0.62,0,6.0(1.0)*,,,,4.5(1.5),0,4.5(1.5),0.092(5) 31-Ga,,,7.288(2),,,,6.675(4),0.16(3),6.83(3),2.75(3) 31-Ga-69,60,3/2,8.043(16),6.3(2),10.5(4),+/-,7.80(4),0.091(11),7.89(4),2.18(5) 31-Ga-71,40,3/2,6.170(11),5.5(6),7.8(1),+/-,5.15(5),0.084(8),5.23(5),3.61(10) @@ -1403,7 +1405,7 @@ def sld_plot(table=None): 38-Sr-88,82.6,0,7.16(6),,,,6.42(11),0,6.42(11),0.058(4) 39-Y-89,100,1/2,7.75(2),8.4(2),5.8(5),+/-,7.55(4),0.15(8),7.70(9),1.28(2) 40-Zr,,,7.16(3),,,,6.44(5),0.02(15),6.46(14),0.185(3) -40-Zr-90,51.48,0,6.5(1),,,,5.1(2),0,5.1(2),0.011(59 +40-Zr-90,51.48,0,6.5(1),,,,5.1(2),0,5.1(2),0.011(5) 40-Zr-91,11.23,5/2,8.8(1),7.9(2),10.1(2),+/-,9.5(2),0.15(4),9.7(2),1.17(10) 40-Zr-92,17.11,0,7.5(2),,,,6.9(4),0,6.9(4),0.22(6) 40-Zr-94,17.4,0,8.3(2),,,,8.4(4),0,8.4(4),0.0499(24) @@ -1467,7 +1469,7 @@ def sld_plot(table=None): 52-Te-120,0.09,0,5.3(5),,,,3.5(7),0,3.5(7),2.3(3) 52-Te-122,2.4,0,3.8(2),,,,1.8(2),0,1.8(2),3.4(5) 52-Te-123,0.87,1/2,-0.05(25),-1.2(2),3.5(2),,0.002(3),0.52(5),0.52(5),418.0(30.0) -52-Te-124,4.61,0,7.95(10),,,,8.0(2),0,8.0(2,6.8(1.3) +52-Te-124,4.61,0,7.95(10),,,,8.0(2),0,8.0(2),6.8(1.3) 52-Te-125,6.99,1/2,5.01(8),4.9(2),5.5(2),,3.17(10),0.008(8),3.18(10),1.55(16) 52-Te-126,18.71,0,5.55(7),,,,3.88(10),0,3.88(10),1.04(15) 52-Te-128,31.79,0,5.88(8),,,,4.36(10),0,4.36(10),0.215(8) @@ -1512,7 +1514,7 @@ def sld_plot(table=None): 61-Pm-147,2.62 Y,7/2,12.6(4),,,,20.0(1.3),1.3(2.0),21.3(1.5),168.4(3.5) 62-Sm,,,0.00(5),,,E,0.422(9),39.0(3.0),39.4(3.0),5922.0(56.0) 62-Sm-144,3.1,0,-3.0(4.0)*,,,,1.0(3.0),0,1.0(3.0),0.7(3) -62-Sm-147,15,7/2,14.0(3.0),,,,25.0(11.0),14.0(19.0.),39.0(16.0),57.0(3.0) +62-Sm-147,15,7/2,14.0(3.0),,,,25.0(11.0),14.0(19.0),39.0(16.0),57.0(3.0) 62-Sm-148,11.2,0,-3.0(4.0)*,,,,1.0(3.0),0,1.0(3.0),2.4(6) 62-Sm-149,13.8,7/2,18.7(28),,,E,63.5(6),137.0(5.0),200.0(5.0),42080.0(400.0) 62-Sm-150,7.4,0,14.0(3.0),,,,25.0(11.0),0,25.0(11.0),104.0(4.0) From f020397ca3b53a92542a4241e985d50ef10de811 Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Tue, 22 Aug 2023 18:10:31 -0400 Subject: [PATCH 06/12] Use uncertainty parser for neutron table, but ignore uncertainty for now --- periodictable/nsf.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/periodictable/nsf.py b/periodictable/nsf.py index e9c5962..d8dbf88 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -1666,14 +1666,8 @@ def fix_number(str): uncertainty. Also accepts a limited range, e.g., <1e-6, which is converted as 1e-6. Missing values are set to 0. """ - if str == '': - return None - idx = str.find('(') - if idx >= 0: - str = str[0:idx] - if str[0] == '<': - str = str[1:] - return float(str) + from .util import parse_uncertainty + return parse_uncertainty(str.replace('<','').replace('*',''))[0] def sld_table(wavelength=1, table=None, isotopes=True): r""" From c32f3d136f9100444bb6273f475223cb5ff3180d Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Wed, 23 Aug 2023 11:53:09 -0400 Subject: [PATCH 07/12] Fix typo in 56-Ba-138 total scattering uncertainty --- periodictable/nsf.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/periodictable/nsf.py b/periodictable/nsf.py index d8dbf88..9df0e7c 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -1493,7 +1493,7 @@ def sld_plot(table=None): 56-Ba-135,6.59,3/2,4.66(10),,,,2.74(12),0.5(5)*,3.2(5),5.8(9) 56-Ba-136,7.81,0,4.90(8),,,,3.03(10),0,3.03(10),0.68(17) 56-Ba-137,11.32,3/2,6.82(10),,,,5.86(17),0.5(5)*,6.4(5),3.6(2) -56-Ba-138,71.66,0,4.83(8),,,,2.94(10),0,2.94(19),0.27(14) +56-Ba-138,71.66,0,4.83(8),,,,2.94(10),0,2.94(10),0.27(14) 57-La,,,8.24(4),,,,8.53(8),1.13(19),9.66(17),8.97(2) 57-La-138,0.09,5,8.0(2.0)*,,,,8.0(4.0),0.5(5)*,8.5(4.0),57.0(6.0) 57-La-139,99.91,7/2,8.24(4),11.4(3),4.5(4),+/-,8.53(8),1.13(15),9.66(17),8.93(4) @@ -1658,8 +1658,6 @@ def sld_plot(table=None): # 63-Eu-151,-2.46,, # 64-Gd-157,-47,-75, - - def fix_number(str): """ Converts strings of the form e.g., 35.24(2)* into numbers without From bba96955100b96209602dd6a2f4b41ce2ebc8c86 Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Wed, 23 Aug 2023 17:46:34 -0400 Subject: [PATCH 08/12] Fix tests which broke because of updated tables --- README.rst | 4 +-- doc/sphinx/guide/formula_grammar.rst | 12 ++++----- doc/sphinx/guide/using.rst | 6 ++--- periodictable/core.py | 2 +- periodictable/fasta.py | 15 +++++++---- periodictable/mass.py | 9 +++++-- periodictable/nsf.py | 8 +++--- periodictable/xsf.py | 2 +- test/test_formulas.py | 10 +++++--- test/test_mass.py | 12 ++++----- test/test_nsf.py | 38 ++++++++++++++++++---------- test/test_xsf.py | 17 ++++++++----- 12 files changed, 81 insertions(+), 54 deletions(-) diff --git a/README.rst b/README.rst index 9d38516..93ed3d2 100644 --- a/README.rst +++ b/README.rst @@ -83,8 +83,8 @@ Modified: * Li-6:Li-7 mass ratio changed from 12.2 to 19.6 (delta = 2.7%) * Isotope percentage changed by 0.1 to 0.5 for B, Zn, Ge, Se, Mo, Er, Yb, Pt, Hg * Atomic weight changed by 0.04% for Zn, 0.02% for S and 0.01% for Li, Ge, Se, Mo -* Zn-70 b_c changed from 6.9 to 6.0 (fixing a typo in the ATI tables) -* Fix typos in uncertainties for the ATI table (Zr-90, Te-124, Sm-147) +* Zn-70 b_c changed from 6.9 to 6.0 in the neutron table (fixing a typo in the original) +* Fix typos in uncertainties in the neutron table (Zr-90, Te-124, Ba-138, Sm-147) 1.6.1 2022-05-18 diff --git a/doc/sphinx/guide/formula_grammar.rst b/doc/sphinx/guide/formula_grammar.rst index b87cad3..0839e7d 100644 --- a/doc/sphinx/guide/formula_grammar.rst +++ b/doc/sphinx/guide/formula_grammar.rst @@ -116,7 +116,7 @@ A formula string is translated into a formula using * Specific mass can be giving with count follwed by mass units: >>> print(formula("5g NaCl // 50mL H2O@1")) - NaCl(H2O)32.4407 + NaCl(H2O)32.4395 Density will be required for materials given by volume. Mass will be stored in the *total_mass* attribute of the resulting formula. @@ -124,7 +124,7 @@ A formula string is translated into a formula using * Multilayers can be specified by thickness: >>> print(formula("1 um Si // 5 nm Cr // 10 nm Au")) - Si119.99CrAu1.41722 + Si119.992CrAu1.41722 Density will be required for each layer. Thickness will be stored in the *total_thickness* attribute of the resulting formula. Thickness can @@ -135,7 +135,7 @@ A formula string is translated into a formula using 20:80 by volume with D2O: >>> print(formula("20%vol (10%wt NaCl@2.16 // H2O@1) // D2O@1n")) - NaCl(H2O)29.1966(D2O)122.794 + NaCl(H2O)29.1956(D2O)122.79 * Empty formulas are supported, e.g., for air or vacuum: @@ -256,7 +256,7 @@ Note that this is different from a 2:1 mixture by weight: >>> mix = mix_by_weight(H2O,2,D2O,1) >>> print("%s %.4g"%(mix,mix.density)) - (H2O)2.2234D2O 1.035 + (H2O)2.22339D2O 1.035 Except in the simplest of cases, the density of the mixture cannot be computed from the densities of the components, and the resulting density @@ -272,8 +272,8 @@ compute molar mass and neutron/xray scattering length density: >>> import periodictable >>> SiO2 = periodictable.formula('SiO2') >>> hydrated = SiO2 + periodictable.formula('3H2O') - >>> print('%s mass %s'%(hydrated,hydrated.mass)) - SiO2(H2O)3 mass 114.13014 + >>> print('%s mass %g'%(hydrated,hydrated.mass)) + SiO2(H2O)3 mass 114.128 >>> rho,mu,inc = periodictable.neutron_sld('SiO2+3H2O',density=1.5,wavelength=4.75) >>> print('%s neutron sld %.3g'%(hydrated,rho)) SiO2(H2O)3 neutron sld 0.849 diff --git a/doc/sphinx/guide/using.rst b/doc/sphinx/guide/using.rst index 48d891b..da7872e 100644 --- a/doc/sphinx/guide/using.rst +++ b/doc/sphinx/guide/using.rst @@ -18,7 +18,7 @@ Access particular elements by name: >>> from periodictable import hydrogen >>> print("H mass %s %s"%(hydrogen.mass, hydrogen.mass_units)) - H mass 1.00794 u + H mass 1.008 u Access particular elements as symbols: @@ -54,7 +54,7 @@ Import all elements: >>> print(periodictable.H) H >>> print(periodictable.H.mass) - 1.00794 + 1.008 Deuterium and tritium are special isotopes named D and T some neutron information is available as 'n': @@ -64,7 +64,7 @@ some neutron information is available as 'n': >>> print("D mass %s"%D.mass) D mass 2.01410177784 >>> print("neutron mass %s"%n.mass) - neutron mass 1.00866491597 + neutron mass 1.0086649159 Process all the elements: diff --git a/periodictable/core.py b/periodictable/core.py index 7324eea..915b9f9 100644 --- a/periodictable/core.py +++ b/periodictable/core.py @@ -378,7 +378,7 @@ def list(self, *props, **kw): >>> from periodictable import elements >>> elements.list('symbol', 'mass', 'density', - ... format="%-2s: %6.2f u %5.2f g/cm^3") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... format="%-2s: %6.2f u %6.2f g/cm^3") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE H : 1.01 u 0.07 g/cm^3 He: 4.00 u 0.12 g/cm^3 Li: 6.94 u 0.53 g/cm^3 diff --git a/periodictable/fasta.py b/periodictable/fasta.py index 7f6c374..6d28750 100644 --- a/periodictable/fasta.py +++ b/periodictable/fasta.py @@ -478,14 +478,14 @@ def fasta_table(): rows += [v for k, v in sorted(NUCLEIC_ACID_COMPONENTS.items())] rows += [Sequence("beta casein", beta_casein)] - print("%20s %7s %7s %7s %5s %5s %5s %5s %5s %5s" + print("%25s %7s %7s %7s %5s %5s %5s %5s %5s %5s" % ("name", "M(H2O)", "M(D2O)", "volume", "den", "#el", "xray", "nH2O", "nD2O", "%D2O match")) for v in rows: protons = sum(num*el.number for el, num in v.natural_formula.atoms.items()) electrons = protons - v.charge Xsld = xray_sld(v.formula, wavelength=elements.Cu.K_alpha) - print("%20s %7.1f %7.1f %7.1f %5.2f %5d %5.2f %5.2f %5.2f %5.1f"%( + print("%25s %7.1f %7.1f %7.1f %5.2f %5d %5.2f %5.2f %5.2f %5.1f"%( v.name, v.mass, v.Dmass, v.cell_volume, v.natural_formula.density, electrons, Xsld[0], v.sld, v.Dsld, v.D2Omatch)) @@ -499,11 +499,15 @@ def test(): # name Hmass Dmass vol den #el xray Hsld Dsld # =========== ======= ======= ======= ===== ===== ===== ===== ===== # beta casein 23561.9 23880.9 30872.9 1.27 12614 11.55 1.68 2.75 + # ... updated for new mass table [2023-08] + # same 23562.3 23881.2 same 1.27 same 1.68 2.75 seq = Sequence("beta casein", beta_casein) - assert abs(seq.mass - 23561.9) < 0.1 - assert abs(seq.Dmass - 23880.9) < 0.1 + density = seq.mass/avogadro_number/seq.cell_volume*1e24 + #print(seq.mass, seq.Dmass, density, seq.sld, seq.Dsld) + assert abs(seq.mass - 23562.3) < 0.1 + assert abs(seq.Dmass - 23881.2) < 0.1 assert abs(seq.cell_volume - 30872.9) < 0.1 - assert abs(seq.mass/avogadro_number/seq.cell_volume*1e24 - 1.267) < 0.01 + assert abs(density - 1.267) < 0.01 assert abs(seq.sld - 1.68) < 0.01 assert abs(seq.Dsld - 2.75) < 0.01 @@ -516,3 +520,4 @@ def test(): if __name__ == "__main__": fasta_table() + #test() diff --git a/periodictable/mass.py b/periodictable/mass.py index 64a1bab..c517d2a 100644 --- a/periodictable/mass.py +++ b/periodictable/mass.py @@ -109,7 +109,8 @@ def init(table, reload=False): # Parse isotope mass table where each line looks like: # z-el-iso,isotope mass(unc)#?,abundance(unc),element mass(unc) - # The abundance and element masses will be superceded below + # The abundance and element masses will be set from other tables, so + # ignore them here. for line in isotope_mass.split('\n'): isotope, m, p, avg = line.split(',') z, sym, iso = isotope.split('-') @@ -117,9 +118,13 @@ def init(table, reload=False): assert el.symbol == sym, \ "Symbol %s does not match %s"%(sym, el.symbol) iso = el.add_isotope(int(iso)) + # Note: new mass table doesn't include nominal values for transuranics + # so use old masses here and override later with new masses. el._mass, el._mass_unc = parse_uncertainty(avg) + #el._mass, el._mass_unc = None, None iso._mass, iso._mass_unc = parse_uncertainty(m) - iso._abundance, iso._abundance_unc = parse_uncertainty(p) + #iso._abundance, iso._abundance_unc = parse_uncertainty(p) + iso._abundance, iso._abundance_unc = 0, 0 # A single neutron is an isotope of element 0 el = table[0] diff --git a/periodictable/nsf.py b/periodictable/nsf.py index 9df0e7c..53689f8 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -1686,8 +1686,8 @@ def sld_table(wavelength=1, table=None, isotopes=True): >>> sld_table(wavelength=4.75) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE Neutron scattering length density table atom mass density sld imag incoh - H 1.008 0.071 -1.582 0.000 10.691 - 1-H 1.008 0.071 -1.583 0.000 10.691 + H 1.008 0.071 -1.582 0.000 10.690 + 1-H 1.008 0.071 -1.583 0.000 10.690 D 2.014 0.141 2.823 0.000 1.705 T 3.016 0.212 2.027 0.000 0.453 He 4.003 0.122 0.598 0.000 0.035 @@ -1869,7 +1869,6 @@ def coherent_comparison_table(table=None, tol=None): Sc 18.40 19.00 -3.2% 45-Sc 18.40 19.00 -3.2% 65-Cu 13.08 14.10 -7.2% - 70-Zn 5.98 4.50 33.0% 84-Sr 3.14 6.00 -47.6% ... @@ -1934,7 +1933,6 @@ def incoherent_comparison_table(table=None, tol=None): Sc 4.50 5.10 -11.8% 45-Sc 4.50 5.10 -11.8% 65-Cu 0.40 1.42 -71.7% - 70-Zn 0.00 -1.48 -100.0% 84-Sr 0.00 2.86 -100.0% ... @@ -1989,3 +1987,5 @@ def main(): if __name__ == "__main__": main() + #coherent_comparison_table(tol=0.5) + #incoherent_comparison_table(tol=0.5) diff --git a/periodictable/xsf.py b/periodictable/xsf.py index 0e924dc..d954136 100644 --- a/periodictable/xsf.py +++ b/periodictable/xsf.py @@ -695,7 +695,7 @@ def sld_table(wavelength=None, table=None): He 1.03 0.00 Li 3.92 0.00 Be 13.93 0.01 - B 18.40 0.01 + B 18.40 0.02 C 18.71 0.03 N 6.88 0.02 O 9.74 0.04 diff --git a/test/test_formulas.py b/test/test_formulas.py index 81ccf4b..832ab7d 100644 --- a/test/test_formulas.py +++ b/test/test_formulas.py @@ -165,11 +165,15 @@ def test(): check_formula(formula('1mm Fe // 1mm Ni'), formula('50%vol Fe // Ni')) check_formula(formula('50%vol Co // Ti'), formula('2mL Co // 2mL Ti')) check_formula(formula('50%wt Co // Ti'), formula('2g Co // 2g Ti')) - check_formula(formula('2mL Co // 2mL Ti'), formula(((1.5922466356368357, Co), (1, Ti)))) - check_formula(formula('2g Co // 2g Ti'), formula(((1, Co), (1.231186412350889, Ti)))) + # The relative quantities change whenenver the mass is updated. + #print(formula('2mL Co // 2mL Ti').structure) + #print(formula('2g Co // 2g Ti').structure) + #print(formula('5g NaCl // 50mL H2O@1').structure) + check_formula(formula('2mL Co // 2mL Ti'), formula(((1.5922467977437773, Co), (1, Ti)))) + check_formula(formula('2g Co // 2g Ti'), formula(((1, Co), (1.2311862870035726, Ti)))) check_formula(formula('5g NaCl // 50mL H2O@1'), formula('5g NaCl // 50g H2O')) check_formula(formula('5g NaCl // 50mL H2O@1'), - formula(((1, Na), (1, Cl), (32.4407, ((2, H), (1, O))))), tol=1e-5) + formula(((1, Na), (1, Cl), (32.43950556758257, ((2, H), (1, O))))), tol=1e-5) assert abs(formula('1mm Fe // 1mm Ni').thickness - 0.002) < 0.002*1e014 assert abs(formula('2g Co // 2g Ti').total_mass - 4) < 4*1e-14 check_mass(formula('2mL Co // 2mL Ti'), mass=2*(Co.density+Ti.density)) diff --git a/test/test_mass.py b/test/test_mass.py index 2fe4618..c5e329d 100644 --- a/test/test_mass.py +++ b/test/test_mass.py @@ -3,8 +3,8 @@ def test(): # Constants defined in the tables. These may be updated from time to time. - Be_12_mass = 12.0269221 - Be_mass = 9.012182 + Be_12_mass = 12.02692210 + Be_mass = 9.0121831 Pb_206_abundance = 24.1 Pb_209_abundance = 0 Pb_mass = 207.2 @@ -13,8 +13,8 @@ def test(): assert periodictable.Be.mass == Be_mass assert abs(periodictable.Be[12].ion[2].mass - (Be_12_mass - 2*periodictable.constants.electron_mass))<1e-12 assert abs(periodictable.Be.ion[2].mass - (Be_mass - 2*periodictable.constants.electron_mass))<1e-12 - assert periodictable.Pb[206].abundance == Pb_206_abundance - assert periodictable.Pb[209].abundance == Pb_209_abundance + assert abs(periodictable.Pb[206].abundance - Pb_206_abundance) < 1e-14 + assert abs(periodictable.Pb[209].abundance - Pb_209_abundance) < 1e-14 assert periodictable.Pb.mass == Pb_mass assert periodictable.n.mass == neutron_mass @@ -31,8 +31,6 @@ def test(): # Check average mass corresponds to abundance information - # Note: should check that this is true within uncertainty, but - # uncertainties are not being loaded. for el in periodictable.elements: abundance=0 mass=0 @@ -42,7 +40,7 @@ def test(): else: abundance += iso.abundance mass += iso.mass*iso.abundance/100. - assert abundance==0 or abs(mass - el.mass)/el.mass < 1e-3,\ + assert abundance==0 or abs(mass - el.mass) < el._mass_unc,\ "avg mass for %s is %g != %g"%(el.symbol,el.mass,mass) diff --git a/test/test_nsf.py b/test/test_nsf.py index c14cbed..9316ae8 100644 --- a/test/test_nsf.py +++ b/test/test_nsf.py @@ -2,6 +2,7 @@ import periodictable from periodictable import elements, formula, nsf from periodictable.nsf import neutron_scattering, neutron_sld +from periodictable.constants import avogadro_number as N_A from math import sqrt, pi def test(): @@ -120,7 +121,8 @@ def test(): assert abs(depth-depth2)<1e-14 # Test energy <=> velocity <=> wavelength - assert abs(nsf.neutron_wavelength_from_velocity(2200) - 1.7981972618436388) < 1e-14 + # PAK: value changes with updated neutron and atomic mass constants [2023-08] + assert abs(nsf.neutron_wavelength_from_velocity(2200) - 1.7981972619684314) < 1e-14 assert abs(nsf.neutron_wavelength(25) - 1.8) < 0.1 assert abs(nsf.neutron_energy(nsf.neutron_wavelength(25)) - 25) < 1e-14 @@ -132,7 +134,8 @@ def test(): assert abs(depth-depth2)<1e-14 def test_formula(): - M = formula('B4C', density=2.52) + density = 2.52 + M = formula('B4C', density=density) sld,xs,depth = neutron_scattering(M,wavelength=4.75) # Compare to Alan Munter's numbers: # SLD=7.65e-6 - 2.34e-7i /A^2 @@ -155,7 +158,9 @@ def test_formula(): # sld_re = 10*number_density * b_c.real # sigma_c = 4*pi/100*((sld_re - 1j*sld_im)/(10*number_density))**2 # coh_xs = sigma_c * number_density - Nb = 0.13732585020640778 + molar_mass = 4*elements.B.mass + elements.C.mass + cell_volume = (molar_mass/density) / N_A * 1e24 + Nb = 5 / cell_volume sld_inc = Nb*sqrt(100/(4*pi)*xs[2]/Nb)*10 coh_xs = Nb*4*pi/100*(abs(sld[0] - 1j*sld[1])/(10*Nb))**2 assert abs(sld[2] - sld_inc) < 1e-14 @@ -251,7 +256,8 @@ def test_energy_dependent(): # Use abundance from mass.py: 97.41% Lu[175] + 2.59% Lu[176] # Note: abundance uses mole fraction. DOI:10.1351/PAC-REP-10-06-02 Lu = elements.Lu - Lu_equiv = "Lu[175]97.41+Lu[176]2.59" + Lu_175_abundance, Lu_176_abundance = 97.401, 2.599 + Lu_equiv = f"Lu[175]{Lu_175_abundance}+Lu[176]{Lu_176_abundance}" # Note: skipping incoherent xs in returned value @@ -260,9 +266,9 @@ def test_energy_dependent(): sld1 = neutron_sld(Lu_equiv, wavelength=wavelength, natural_density=Lu.density) sld2 = Lu.neutron.sld(wavelength=wavelength) # sld elements are arrays of length 4 - #print("multiple"); print(sld1); print(sld2) assert all(len(v) == 4 for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14).all() for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14).all() + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14).all() # Length 1 wavelength energy dependent sld1 = neutron_sld(Lu_equiv, wavelength=wavelength[:1], natural_density=Lu.density) @@ -270,7 +276,8 @@ def test_energy_dependent(): # sld elements are arrays of length 1 #print("length 1", sld1, sld2) assert all(len(v) == 1 for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14).all() for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14).all() + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14).all() # Scalar wavelength energy dependent sld1 = neutron_sld(Lu_equiv, wavelength=wavelength[0], natural_density=Lu.density) @@ -278,33 +285,37 @@ def test_energy_dependent(): # sld elements are scalars; note no .all() on the comparison #print("scalar", sld1, sld2) assert all(np.isscalar(v) for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14) for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14).all() + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14).all() # Check that composite sld calculator works with energy dependence and # various wavelength vectors. materials = formula('Lu[175]'), formula('Lu[176]') - weights = np.array((97.41, 2.59)) + weights = np.array((Lu_175_abundance, Lu_176_abundance)) # Multiple wavelength sld1 = neutron_sld(Lu_equiv, wavelength=wavelength, density=Lu.density) calc = neutron_composite_sld(materials, wavelength=wavelength) sld2 = calc(weights, density=Lu.density) assert all(len(v) == 4 for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14).all() for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14).all() + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14).all() # Length 1 wavelength sld1 = neutron_sld(Lu_equiv, wavelength=wavelength[:1], density=Lu.density) calc = neutron_composite_sld(materials, wavelength=wavelength[:1]) sld2 = calc(weights, density=Lu.density) assert all(len(v) == 1 for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14).all() for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14).all() + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14).all() # scalar wavelength sld1 = neutron_sld(Lu_equiv, wavelength=wavelength[0], density=Lu.density) calc = neutron_composite_sld(materials, wavelength=wavelength[0]) sld2 = calc(weights, density=Lu.density) assert all(np.isscalar(v) for v in sld1 + sld2) - assert all((abs((v-w)/v) < 1e-14) for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14) + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14) # Check against Alex Grutter spreadsheet values computed from Lynn&Seeger wavelength = neutron_wavelength(80) # look at 80 meV in the table @@ -313,7 +324,8 @@ def test_energy_dependent(): # reconstruct density from the given number density density = elements.Gd.mass*number_density*1e21/NA sld2 = neutron_sld("Gd", wavelength=wavelength, density=density) - assert all(abs((v-w)/v)<1e-14 for v, w in zip(sld1[:2], sld2[:2])) + assert (abs((sld1[0]-sld2[0])/sld1[0]) < 1e-14) + assert (abs((sld1[1]-sld2[1])/sld1[1]) < 1e-14) def time_composite(): from periodictable.nsf import neutron_composite_sld diff --git a/test/test_xsf.py b/test/test_xsf.py index ec53e0c..4cd8a79 100644 --- a/test/test_xsf.py +++ b/test/test_xsf.py @@ -1,4 +1,4 @@ -import numpy +import numpy as np from numpy import pi, isnan from periodictable import formula from periodictable import Cu,Mo,Ni,Fe,Si,H,D,O @@ -26,7 +26,7 @@ def test_xsf(): Fe_rho,Fe_mu = Fe.xray.sld(wavelength=Cu.K_alpha) assert abs(Fe_rho-59.45) < 0.01 Si_rho,Si_mu = Si.xray.sld(energy=8.050) - assert abs(Si_rho-20.0701) < 0.0001 + assert abs(Si_rho-20.0705) < 0.0001 assert abs(Si_mu-0.4572) < 0.0001 # Check that wavelength is the default @@ -151,11 +151,14 @@ def test_refl(): 704.226 2.655170E-02 1000.00 1.240138E-03""") - e,R2 = numpy.loadtxt(data2).T - e,R3 = numpy.loadtxt(data3).T - R = mirror_reflectivity(energy=e*1e-3,angle=[2,3],compound='SiO2',density=2.2, - roughness=30) - assert numpy.max(abs((R-numpy.vstack([R2,R3]))/R)) < 1e-4 + e,R2 = np.loadtxt(data2).T + e,R3 = np.loadtxt(data3).T + R = mirror_reflectivity( + energy=e*1e-3, angle=[2,3], + compound='SiO2', density=2.2, roughness=30) + #print(R.T) + #print(((R - np.vstack([R2,R3]))/R).T) + assert np.max(abs((R-np.vstack([R2,R3]))/R)) < 2e-4 def main(): From ee2f2d38fce0beff0fc90c7af1a571cc235f313a Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 25 Aug 2023 11:23:59 -0400 Subject: [PATCH 09/12] Fix build issues with docs? --- MANIFEST.in | 10 ++++++---- periodictable/mass.py | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index db86edc..77181ae 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,9 @@ include LICENSE.txt -include doc -include periodictable/xsf/* -include periodictable/activation.dat +graft doc prune doc/sphinx/_build prune doc/sphinx/build -exclude build dist *.pyc +prune */__pycache__ +prune */*/__pycache__ +prune */*/*/__pycache__ +#recursive-exclude __pycache__ * +#exclude build dist *.pyc __pycache__/* diff --git a/periodictable/mass.py b/periodictable/mass.py index c517d2a..ea07887 100644 --- a/periodictable/mass.py +++ b/periodictable/mass.py @@ -75,8 +75,9 @@ def mass(isotope): Atomic weight of the element. Reference: - *Wang. M., Huang. W. J., Kondev. F. G., Audi. G., Naimi. S., The AME - 2020 atomic mass evaluation (II). Tables, graphs and references * + Wang. M., Huang. W. J., Kondev. F. G., Audi. G., Naimi. S. (2021) + The AME 2020 atomic mass evaluation (II). Tables, graphs and references + *Chinese Physics C*, Volume 45, Number 3 """ return isotope._mass @@ -91,8 +92,8 @@ def abundance(isotope): *abundance* : float | % Reference: - *Coursey. J. S., Schwab. D. J, and Dragoset. R. A., NIST Atomic - Weights and Isotopic Composition Database.* + J. Meija et al. (2016) Isotopic compositions of the elements 2013 + *Pure and Applied Chemistry* 88, 293-306. """ return isotope._abundance From 58c3d08912e02d773a7f9ffdb91dc5b35e7521ba Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 25 Aug 2023 15:01:25 -0400 Subject: [PATCH 10/12] Update docs --- README.rst | 39 +++++++++++++++++---------------------- periodictable/nsf.py | 29 ++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/README.rst b/README.rst index 93ed3d2..28fe940 100644 --- a/README.rst +++ b/README.rst @@ -5,23 +5,21 @@ Extensible periodic table of the elements This package provides a periodic table of the elements with support for mass, density and xray/neutron scattering information. -Masses, densities and natural abundances come from the -NIST Physics Laboratory, but do not represent a critical -evaluation by NIST scientists. - Neutron scattering calculations use values collected by the -Atomic Institute of the Austrian Universities. These values -do corresponding to those from other packages, though there -are some differences depending to the tables used. Bound -coherent neutron scattering for gold in particular is significantly -different from older value: 7.63(6) as measured in 1974 -compared to 7.90(7) as measured in 1990. - -X-ray scattering calculations use a combination of empirical and -theoretical values from the LBL Center for X-ray Optics. These -values differ from those given in other sources such as the -International Tables for Crystallography, Volume C, and so may -give different results from other packages. +Atomic Institute of the Austrian Universities as they appear in the neutron +data booklet, with support for some energy dependent scattering +in rare earth elements given by Lynn and Seeger (1990). X-ray scattering +calculations use a combination of empirical and theoretical values from +the LBL Center for X-ray Optics. + +Tabulated values differ from those given in other sources such as the +International Tables for Crystallography, Volume C, and so computed +cross sections may give different results from other packages. + +Neutron activation calculations are based on Shleien (1998), with +isotopes important to health physics. They do not perform a full +activation analysis, but instead give a gross estimate of the amount +of activation expected for a sample in the beam. Install using:: @@ -62,12 +60,9 @@ Known issues isotope proportions and density computed in neutron_sld(). This may change in a future release. -* The mass and composition tables are out of date. This package uses tables - from 1997 but IUPAC produced new tables in 2009. - * Incoherent scattering calculations for energy-dependent rare earth elements is underestimated. The calculation requires bound incoherent scattering - lengths (b_i) and the bound coherent lengths (b_c), but only b_c is + length (b_i) but only the bound coherent scattering length (b_c) is included. Change history @@ -79,11 +74,11 @@ Change history Modified: * Move to IAEA AME2020 for isotope mass -* Move to IUPAC CIAAW for atomic weight and isotopic abundance +* Move to IUPAC CIAAW 2021 for atomic weight and isotopic abundance * Li-6:Li-7 mass ratio changed from 12.2 to 19.6 (delta = 2.7%) * Isotope percentage changed by 0.1 to 0.5 for B, Zn, Ge, Se, Mo, Er, Yb, Pt, Hg * Atomic weight changed by 0.04% for Zn, 0.02% for S and 0.01% for Li, Ge, Se, Mo -* Zn-70 b_c changed from 6.9 to 6.0 in the neutron table (fixing a typo in the original) +* Neutron b_c changed for Zn-70 from 6.9 to 6.0 (fixes a typo in the original table) * Fix typos in uncertainties in the neutron table (Zr-90, Te-124, Ba-138, Sm-147) diff --git a/periodictable/nsf.py b/periodictable/nsf.py index 53689f8..2c830fa 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -75,13 +75,24 @@ For private tables use :func:`init` to set the data. The neutron scattering information table is reproduced from the Atomic -Institute for Austrian Universities\ [#Rauch2003]_ (retrieve March 2008): +Institute for Austrian Universities\ [#Rauch2003]_ (retrieved March 2008): http://www.ati.ac.at/~neutropt/scattering/table.html The above site has references to the published values for every entry in the table. We have included these in the documentation directory -associated with the periodictable package. +within the periodictable source package. Some typographical errors have +been fixed. In particular, Zn-70 has b_c listed as 6.9 in the table, +but 6.0 in the source materials for the table. + +Alternative tables from Sears\ [#Sears1992]\ [#Sears2006] and Dawidowski, +et al.\ [#Dawidowski2013] make different choices for the recommended values. +These are noted in periodictable issue #59 +(`https://github.com/pkienzle/periodictable/issues/59`_) +with changes from Sears to Rauch +`here `_ +and from Rauch to Dawidowski +`here `_. .. Note: @@ -113,7 +124,7 @@ In Prince, E. ed. Intl. Tables for Crystallography C. Kluwer Academic Publishers. pp 444-454. (https://it.iucr.org/Cb/ch4o4v0001/sec4o4o4/) - doi: 10.1107/97809553602060000103 + doi:10.1107/97809553602060000103 .. [#Sears1992] Sears, V.F. (1992) Neutron scattering lengths and cross sections. @@ -130,11 +141,19 @@ .. [#Smith2006] Smith, G.S. and Majkrzak, C.M. (2006) 2.9 Neutron reflectometry. In E. Prince ed. Intl. Tables for Crystallography C. - Wiley InterScience. pp 126-146. doi: 10.1107/97809553602060000584 + Wiley InterScience. pp 126-146. doi:10.1107/97809553602060000584 .. [#Glinka2011] Glinka, C.J. (2011) Incoherent Neutron Scattering from Multi-element Materials. - J. Appl. Cryst. 44, 618-624. doi: 10.1107/S0021889811008223 + J. Appl. Cryst. 44, 618-624. doi:10.1107/S0021889811008223 + +.. [#Dawidowski2013] Dawidowski, J., Granada, J. R., Santisteban, + J. R., Cantargi, F., & Palomino, L. A. R. (2013). + Appendix—Neutron Scattering Lengths and Cross Sections. + In F. Fernandez-Alonso & D. L. Price (Eds.), + Experimental Methods in the Physical Sciences (Vol. 44, pp. 471–528). + Academic Press. doi:10.1016/B978-0-12-398374-9.09989-7 + """ from __future__ import print_function From 9605ef1a0b68a49e1ad92b590f9aa93d0b5ac9be Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Fri, 25 Aug 2023 16:00:13 -0400 Subject: [PATCH 11/12] Fix doc syntax --- periodictable/nsf.py | 8 ++++---- test/test_nsf.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/periodictable/nsf.py b/periodictable/nsf.py index 2c830fa..35a2cdb 100644 --- a/periodictable/nsf.py +++ b/periodictable/nsf.py @@ -77,7 +77,7 @@ The neutron scattering information table is reproduced from the Atomic Institute for Austrian Universities\ [#Rauch2003]_ (retrieved March 2008): -http://www.ati.ac.at/~neutropt/scattering/table.html +``_ The above site has references to the published values for every entry in the table. We have included these in the documentation directory @@ -88,11 +88,11 @@ Alternative tables from Sears\ [#Sears1992]\ [#Sears2006] and Dawidowski, et al.\ [#Dawidowski2013] make different choices for the recommended values. These are noted in periodictable issue #59 -(`https://github.com/pkienzle/periodictable/issues/59`_) +``_ with changes from Sears to Rauch -`here `_ +`(a) `__ and from Rauch to Dawidowski -`here `_. +`(b) `__. .. Note: diff --git a/test/test_nsf.py b/test/test_nsf.py index 9316ae8..e63df22 100644 --- a/test/test_nsf.py +++ b/test/test_nsf.py @@ -257,7 +257,7 @@ def test_energy_dependent(): # Note: abundance uses mole fraction. DOI:10.1351/PAC-REP-10-06-02 Lu = elements.Lu Lu_175_abundance, Lu_176_abundance = 97.401, 2.599 - Lu_equiv = f"Lu[175]{Lu_175_abundance}+Lu[176]{Lu_176_abundance}" + Lu_equiv = "Lu[175]%g+Lu[176]%g"%(Lu_175_abundance, Lu_176_abundance) # Note: skipping incoherent xs in returned value From 55ce71c4590e8782d3dd545e2ffc74fe4219bfae Mon Sep 17 00:00:00 2001 From: Paul Kienzle Date: Tue, 13 Feb 2024 17:26:53 -0500 Subject: [PATCH 12/12] fix precision in mass example --- doc/sphinx/guide/formula_grammar.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sphinx/guide/formula_grammar.rst b/doc/sphinx/guide/formula_grammar.rst index 61414c0..043d155 100644 --- a/doc/sphinx/guide/formula_grammar.rst +++ b/doc/sphinx/guide/formula_grammar.rst @@ -273,7 +273,7 @@ compute molar mass and neutron/xray scattering length density: >>> import periodictable >>> SiO2 = periodictable.formula('SiO2') >>> hydrated = SiO2 + periodictable.formula('3H2O') - >>> print(f"{hydrated} mass {hydrated.mass}") + >>> print(f"{hydrated} mass {hydrated.mass:.3f}") SiO2(H2O)3 mass 114.128 >>> rho,mu,inc = periodictable.neutron_sld('SiO2+3H2O',density=1.5,wavelength=4.75) >>> print(f"{hydrated} neutron sld {rho:.3g}")