diff --git a/README.md b/README.md index f2a5189..703ea4d 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Once installed or cloned, the data is available as a single dataframe indexed on >>> from nuclearmasses.mass_table import MassTable >>> df = MassTable().full_data ``` -You can then interrogate, or extract, what ever information you want. +You can then interrogate, or extract, whatever 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']] @@ -61,7 +61,7 @@ TableYear 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 +Or how does the mass excess of gold vary across the isotopic 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 @@ -115,7 +115,15 @@ TableYear 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). +We use a combination of [isort](https://pycqa.github.io/isort/), [ruff](https://docs.astral.sh/ruff/) and [mypy](https://www.mypy-lang.org/) to keep things tidy and hopefully catch errors and bugs before they happen. +The command below returns no errors or issues so should be run after any code changes. +We might add a CI pipeline in the future, but for the moment, it's a manual process. +```bash +isort . && ruff format && ruff check && mypy nuclearmasses +``` + ## Known issues + - [#5](https://github.com/php1ic/nuclearmasses/issues/5) 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']] diff --git a/nuclearmasses/ame_mass_file.py b/nuclearmasses/ame_mass_file.py index 6139fe2..e874ff9 100644 --- a/nuclearmasses/ame_mass_file.py +++ b/nuclearmasses/ame_mass_file.py @@ -134,15 +134,15 @@ def __init__(self, year: int): 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), - ] + (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), + ] diff --git a/nuclearmasses/ame_mass_parse.py b/nuclearmasses/ame_mass_parse.py index 6976a76..8fa123f 100644 --- a/nuclearmasses/ame_mass_parse.py +++ b/nuclearmasses/ame_mass_parse.py @@ -26,53 +26,53 @@ def _column_names(self) -> list[str]: match self.year: case _: return [ - "Z", - "A", - "AMEMassExcess", - "AMEMassExcessError", - "BindingEnergyPerA", - "BindingEnergyPerAError", - "BetaDecayEnergy", - "BetaDecayEnergyError", - "AtomicNumber", - "AtomicMass", - "AtomicMassError" - ] + "Z", + "A", + "AMEMassExcess", + "AMEMassExcessError", + "BindingEnergyPerA", + "BindingEnergyPerAError", + "BetaDecayEnergy", + "BetaDecayEnergyError", + "AtomicNumber", + "AtomicMass", + "AtomicMassError", + ] def _data_types(self) -> dict: """Set the data type depending on the year""" match self.year: case _: return { - "TableYear": "Int64", - "Symbol": "string", - "N": "Int64", - "Z": "Int64", - "A": "Int64", - "AMEMassExcess": "float64", - "AMEMassExcessError": "float64", - "BindingEnergyPerA": "float64", - "BindingEnergyPerAError": "float64", - "BetaDecayEnergy": "float64", - "BetaDecayEnergyError": "float64", - "AtomicMass": "float64", - "AtomicMassError": "float64", - } + "TableYear": "Int64", + "Symbol": "string", + "N": "Int64", + "Z": "Int64", + "A": "Int64", + "AMEMassExcess": "float64", + "AMEMassExcessError": "float64", + "BindingEnergyPerA": "float64", + "BindingEnergyPerAError": "float64", + "BetaDecayEnergy": "float64", + "BetaDecayEnergyError": "float64", + "AtomicMass": "float64", + "AtomicMassError": "float64", + } def _na_values(self) -> dict: """Set the columns that have placeholder values""" match self.year: case 1983: return { - "A": [''], - "BetaDecayEnergy": ['', '*'], - "BetaDecayEnergyError": ['', '*'], - } + "A": [""], + "BetaDecayEnergy": ["", "*"], + "BetaDecayEnergyError": ["", "*"], + } case _: return { - "BetaDecayEnergy": ['', '*'], - "BetaDecayEnergyError": ['', '*'], - } + "BetaDecayEnergy": ["", "*"], + "BetaDecayEnergyError": ["", "*"], + } def read_file(self) -> pd.DataFrame: """Read the file using it's known format @@ -83,43 +83,48 @@ def read_file(self) -> pd.DataFrame: """ try: df = pd.read_fwf( - self.filename, - colspecs=self.column_limits, - names=self._column_names(), - na_values=self._na_values(), - keep_default_na=False, - on_bad_lines='warn', - skiprows=self.HEADER, - skipfooter=self.FOOTER - ) + self.filename, + colspecs=self.column_limits, + names=self._column_names(), + na_values=self._na_values(), + keep_default_na=False, + on_bad_lines="warn", + skiprows=self.HEADER, + skipfooter=self.FOOTER, + ) # We use the NUBASE data to define whether or not an isotope is experimentally measured, # so for this data we'll just drop any and all '#' characters df.replace("#", "", regex=True, inplace=True) if self.year == 1983: # The column headers and units are repeated in the 1983 table - df = df[(df['A'] != 'A') & (~df["AMEMassExcess"].astype("string").str.contains('keV', na=False))] + df = df[(df["A"] != "A") & (~df["AMEMassExcess"].astype("string").str.contains("keV", na=False))] # The A value is not in the column if it doesn't change so we need to fill down - df['A'] = df['A'].ffill() + df["A"] = df["A"].ffill() # Isomeric states are sometimes included in this version of the file # For each row in the dataframe, if the previous row has equal A and Z, drop the current row - df = df[~((df['A'] == df['A'].shift()) & (df['Z'] == df['Z'].shift()))] + df = df[~((df["A"] == df["A"].shift()) & (df["Z"] == df["Z"].shift()))] if self.year == 1983 or self.year == 1993 or self.year == 1995: - df["BindingEnergyPerA"] = df["BindingEnergyPerA"].astype(float) / df['A'].astype(float) - df["BindingEnergyPerAError"] = df["BindingEnergyPerAError"].astype(float) / df['A'].astype(float) + df["BindingEnergyPerA"] = df["BindingEnergyPerA"].astype(float) / df["A"].astype(float) + df["BindingEnergyPerAError"] = df["BindingEnergyPerAError"].astype(float) / df["A"].astype(float) df["TableYear"] = self.year df["N"] = pd.to_numeric(df["A"]) - pd.to_numeric(df["Z"]) df["Symbol"] = pd.to_numeric(df["Z"]).map(self.z_to_symbol) # Combine the two columns to create the atomic mass then drop the redundant column - df["AtomicMass"] = df["AtomicNumber"].astype("string") + "." + df["AtomicMass"].astype("string").str.replace(".", "", regex=False) + # Pandas is happy to use '+' for any type, but mypy doesn't like it, hence the use of str.cat() + df["AtomicMass"] = ( + df["AtomicNumber"] + .astype("string") + .str.cat(df["AtomicMass"].astype("string").str.replace(".", "", regex=False), sep=".") + ) df = df.drop(columns=["AtomicNumber"]) # We need to rescale the error value because we combined the two columns above df = df.assign(AtomicMassError=df["AtomicMassError"].astype(float) / 1.0e6) - - return df.astype(self._data_types()) except ValueError as e: print(f"Parsing error: {e}") + + return df.astype(self._data_types()) diff --git a/nuclearmasses/ame_reaction_1_file.py b/nuclearmasses/ame_reaction_1_file.py index a98804e..39926cd 100644 --- a/nuclearmasses/ame_reaction_1_file.py +++ b/nuclearmasses/ame_reaction_1_file.py @@ -107,18 +107,18 @@ def __init__(self, year: int): self.END_DQBN = 125 self.column_limits = [ - (self.START_R1_A, self.END_R1_A), - (self.START_R1_Z, self.END_R1_Z), - (self.START_S2N, self.END_S2N), - (self.START_DS2N, self.END_DS2N), - (self.START_S2P, self.END_S2P), - (self.START_DS2P, self.END_DS2P), - (self.START_QA, self.END_QA), - (self.START_DQA, self.END_DQA), - (self.START_Q2B, self.END_Q2B), - (self.START_DQ2B, self.END_DQ2B), - (self.START_QEP, self.END_QEP), - (self.START_DQEP, self.END_DQEP), - (self.START_QBN, self.END_QBN), - (self.START_DQBN, self.END_DQBN), - ] + (self.START_R1_A, self.END_R1_A), + (self.START_R1_Z, self.END_R1_Z), + (self.START_S2N, self.END_S2N), + (self.START_DS2N, self.END_DS2N), + (self.START_S2P, self.END_S2P), + (self.START_DS2P, self.END_DS2P), + (self.START_QA, self.END_QA), + (self.START_DQA, self.END_DQA), + (self.START_Q2B, self.END_Q2B), + (self.START_DQ2B, self.END_DQ2B), + (self.START_QEP, self.END_QEP), + (self.START_DQEP, self.END_DQEP), + (self.START_QBN, self.END_QBN), + (self.START_DQBN, self.END_DQBN), + ] diff --git a/nuclearmasses/ame_reaction_1_parse.py b/nuclearmasses/ame_reaction_1_parse.py index 4421652..a9d3a2f 100644 --- a/nuclearmasses/ame_reaction_1_parse.py +++ b/nuclearmasses/ame_reaction_1_parse.py @@ -1,4 +1,5 @@ """Extract the data from the first reaction file.""" + import logging import pathlib @@ -25,65 +26,65 @@ def _column_names(self) -> list[str]: match self.year: case _: return [ - "A", - "Z", - "TwoNeutronSeparationEnergy", - "TwoNeutronSeparationEnergyError", - "TwoProtonSeparationEnergy", - "TwoProtonSeparationEnergyError", - "QAlpha", - "QAlphaError", - "QTwoBeta", - "QTwoBetaError", - "QEpsilon", - "QEpsilonError", - "QBetaNeutron", - "QBetaNeutronError", - ] + "A", + "Z", + "TwoNeutronSeparationEnergy", + "TwoNeutronSeparationEnergyError", + "TwoProtonSeparationEnergy", + "TwoProtonSeparationEnergyError", + "QAlpha", + "QAlphaError", + "QTwoBeta", + "QTwoBetaError", + "QEpsilon", + "QEpsilonError", + "QBetaNeutron", + "QBetaNeutronError", + ] def _data_types(self) -> dict: """Set the data type depending on the year""" match self.year: case _: return { - "TableYear": "Int64", - "Symbol": "string", - "A": "Int64", - "Z": "Int64", - "N": "Int64", - "TwoNeutronSeparationEnergy": "float64", - "TwoNeutronSeparationEnergyError": "float64", - "TwoProtonSeparationEnergy": "float64", - "TwoProtonSeparationEnergyError": "float64", - "QAlpha": "float64", - "QAlphaError": "float64", - "QTwoBeta": "float64", - "QTwoBetaError": "float64", - "QEpsilon": "float64", - "QEpsilonError": "float64", - "QBetaNeutron": "float64", - "QBetaNeutronError": "float64", - } + "TableYear": "Int64", + "Symbol": "string", + "A": "Int64", + "Z": "Int64", + "N": "Int64", + "TwoNeutronSeparationEnergy": "float64", + "TwoNeutronSeparationEnergyError": "float64", + "TwoProtonSeparationEnergy": "float64", + "TwoProtonSeparationEnergyError": "float64", + "QAlpha": "float64", + "QAlphaError": "float64", + "QTwoBeta": "float64", + "QTwoBetaError": "float64", + "QEpsilon": "float64", + "QEpsilonError": "float64", + "QBetaNeutron": "float64", + "QBetaNeutronError": "float64", + } def _na_values(self) -> dict: """Set the columns that have placeholder values""" match self.year: case _: return { - "A": [''], - "TwoNeutronSeparationEnergy": ['', '*'], - "TwoNeutronSeparationEnergyError": ['', '*'], - "TwoProtonSeparationEnergy": ['', '*'], - "TwoProtonSeparationEnergyError": ['', '*'], - "QAlpha": ['', '*'], - "QAlphaError": ['', '*'], - "QTwoBeta": ['', '*'], - "QTwoBetaError": ['', '*'], - "QEpsilon": ['', '*'], - "QEpsilonError": ['', '*'], - "QBetaNeutron": ['', '*'], - "QBetaNeutronError": ['', '*'], - } + "A": [""], + "TwoNeutronSeparationEnergy": ["", "*"], + "TwoNeutronSeparationEnergyError": ["", "*"], + "TwoProtonSeparationEnergy": ["", "*"], + "TwoProtonSeparationEnergyError": ["", "*"], + "QAlpha": ["", "*"], + "QAlphaError": ["", "*"], + "QTwoBeta": ["", "*"], + "QTwoBetaError": ["", "*"], + "QEpsilon": ["", "*"], + "QEpsilonError": ["", "*"], + "QBetaNeutron": ["", "*"], + "QBetaNeutronError": ["", "*"], + } def read_file(self) -> pd.DataFrame: """Read the file using it's known format @@ -94,29 +95,29 @@ def read_file(self) -> pd.DataFrame: """ try: df = pd.read_fwf( - self.filename, - colspecs=self.column_limits, - names=self._column_names(), - na_values=self._na_values(), - keep_default_na=False, - on_bad_lines='warn', - skiprows=self.HEADER, - skipfooter=self.FOOTER - ) + self.filename, + colspecs=self.column_limits, + names=self._column_names(), + na_values=self._na_values(), + keep_default_na=False, + on_bad_lines="warn", + skiprows=self.HEADER, + skipfooter=self.FOOTER, + ) # We use the NUBASE data to define whether or not an isotope is experimentally measured, # so for this data we'll just drop any and all '#' characters df.replace("#", "", regex=True, inplace=True) if self.year == 1983: # The column headers and units are repeated in the 1983 table - df = df[(df['A'] != 'A') & (df['Z'] != '')] + df = df[(df["A"] != "A") & (df["Z"] != "")] # The A value is not in the column if it doesn't change so we need to fill down - df['A'] = df['A'].ffill() + df["A"] = df["A"].ffill() df["TableYear"] = self.year df["N"] = pd.to_numeric(df["A"]) - pd.to_numeric(df["Z"]) df["Symbol"] = pd.to_numeric(df["Z"]).map(self.z_to_symbol) - - return df.astype(self._data_types()) except ValueError as e: print(f"Parsing error: {e}") + + return df.astype(self._data_types()) diff --git a/nuclearmasses/ame_reaction_2_file.py b/nuclearmasses/ame_reaction_2_file.py index 1d3610b..1449997 100644 --- a/nuclearmasses/ame_reaction_2_file.py +++ b/nuclearmasses/ame_reaction_2_file.py @@ -106,18 +106,18 @@ def __init__(self, year: int): self.END_DQNA = 125 self.column_limits = [ - (self.START_R2_A, self.END_R2_A), - (self.START_R2_Z, self.END_R2_Z), - (self.START_SN, self.END_SN), - (self.START_DSN, self.END_DSN), - (self.START_SP, self.END_SP), - (self.START_DSP, self.END_DSP), - (self.START_Q4B, self.END_Q4B), - (self.START_DQ4B, self.END_DQ4B), - (self.START_QDA, self.END_QDA), - (self.START_DQDA, self.END_DQDA), - (self.START_QPA, self.END_QPA), - (self.START_DQPA, self.END_DQPA), - (self.START_QNA, self.END_QNA), - (self.START_DQNA, self.END_DQNA), - ] + (self.START_R2_A, self.END_R2_A), + (self.START_R2_Z, self.END_R2_Z), + (self.START_SN, self.END_SN), + (self.START_DSN, self.END_DSN), + (self.START_SP, self.END_SP), + (self.START_DSP, self.END_DSP), + (self.START_Q4B, self.END_Q4B), + (self.START_DQ4B, self.END_DQ4B), + (self.START_QDA, self.END_QDA), + (self.START_DQDA, self.END_DQDA), + (self.START_QPA, self.END_QPA), + (self.START_DQPA, self.END_DQPA), + (self.START_QNA, self.END_QNA), + (self.START_DQNA, self.END_DQNA), + ] diff --git a/nuclearmasses/ame_reaction_2_parse.py b/nuclearmasses/ame_reaction_2_parse.py index 56daa61..6ca7aa9 100644 --- a/nuclearmasses/ame_reaction_2_parse.py +++ b/nuclearmasses/ame_reaction_2_parse.py @@ -1,4 +1,5 @@ """Extract the date from the second reaction file.""" + import logging import pathlib @@ -25,65 +26,65 @@ def _column_names(self) -> list[str]: match self.year: case _: return [ - "A", - "Z", - "OneNeutronSeparationEnergy", - "OneNeutronSeparationEnergyError", - "OneProtonSeparationEnergy", - "OneProtonSeparationEnergyError", - "QFourBeta", - "QFourBetaError", - "QDeuteronAlpha", - "QDeuteronAlphaError", - "QProtonAlpha", - "QProtonAlphaError", - "QNeutronAlpha", - "QNeutronAlphaError", - ] + "A", + "Z", + "OneNeutronSeparationEnergy", + "OneNeutronSeparationEnergyError", + "OneProtonSeparationEnergy", + "OneProtonSeparationEnergyError", + "QFourBeta", + "QFourBetaError", + "QDeuteronAlpha", + "QDeuteronAlphaError", + "QProtonAlpha", + "QProtonAlphaError", + "QNeutronAlpha", + "QNeutronAlphaError", + ] def _data_types(self) -> dict: """Set the data type depending on the year""" match self.year: case _: return { - "TableYear": "Int64", - "Symbol": "string", - "A": "Int64", - "Z": "Int64", - "N": "Int64", - "OneNeutronSeparationEnergy": "float64", - "OneNeutronSeparationEnergyError": "float64", - "OneProtonSeparationEnergy": "float64", - "OneProtonSeparationEnergyError": "float64", - "QFourBeta": "float64", - "QFourBetaError": "float64", - "QDeuteronAlpha": "float64", - "QDeuteronAlphaError": "float64", - "QProtonAlpha": "float64", - "QProtonAlphaError": "float64", - "QNeutronAlpha": "float64", - "QNeutronAlphaError": "float64", - } + "TableYear": "Int64", + "Symbol": "string", + "A": "Int64", + "Z": "Int64", + "N": "Int64", + "OneNeutronSeparationEnergy": "float64", + "OneNeutronSeparationEnergyError": "float64", + "OneProtonSeparationEnergy": "float64", + "OneProtonSeparationEnergyError": "float64", + "QFourBeta": "float64", + "QFourBetaError": "float64", + "QDeuteronAlpha": "float64", + "QDeuteronAlphaError": "float64", + "QProtonAlpha": "float64", + "QProtonAlphaError": "float64", + "QNeutronAlpha": "float64", + "QNeutronAlphaError": "float64", + } def _na_values(self) -> dict: """Set the columns that have placeholder values""" match self.year: case _: return { - "A": [''], - "OneNeutronSeparationEnergy": ['', '*'], - "OneNeutronSeparationEnergyError": ['', '*'], - "OneProtonSeparationEnergy": ['', '*'], - "OneProtonSeparationEnergyError": ['', '*'], - "QFourBeta": ['', '*'], - "QFourBetaError": ['', '*'], - "QDeuteronAlpha": ['', '*'], - "QDeuteronAlphaError": ['', '*'], - "QProtonAlpha": ['', '*'], - "QProtonAlphaError": ['', '*'], - "QNeutronAlpha": ['', '*'], - "QNeutronAlphaError": ['', '*'], - } + "A": [""], + "OneNeutronSeparationEnergy": ["", "*"], + "OneNeutronSeparationEnergyError": ["", "*"], + "OneProtonSeparationEnergy": ["", "*"], + "OneProtonSeparationEnergyError": ["", "*"], + "QFourBeta": ["", "*"], + "QFourBetaError": ["", "*"], + "QDeuteronAlpha": ["", "*"], + "QDeuteronAlphaError": ["", "*"], + "QProtonAlpha": ["", "*"], + "QProtonAlphaError": ["", "*"], + "QNeutronAlpha": ["", "*"], + "QNeutronAlphaError": ["", "*"], + } def read_file(self) -> pd.DataFrame: """Read the file using it's known format @@ -94,33 +95,33 @@ def read_file(self) -> pd.DataFrame: """ try: df = pd.read_fwf( - self.filename, - colspecs=self.column_limits, - names=self._column_names(), - na_values=self._na_values(), - keep_default_na=False, - on_bad_lines='warn', - skiprows=self.HEADER, - skipfooter=self.FOOTER - ) + self.filename, + colspecs=self.column_limits, + names=self._column_names(), + na_values=self._na_values(), + keep_default_na=False, + on_bad_lines="warn", + skiprows=self.HEADER, + skipfooter=self.FOOTER, + ) # We use the NUBASE data to define whether or not an isotope is experimentally measured, # so for this data we'll just drop any and all '#' characters df.replace("#", "", regex=True, inplace=True) if self.year == 1983: # The column headers and units are repeated in the 1983 table - df = df[(df['A'] != 'A') & (df['Z'] != '')] + df = df[(df["A"] != "A") & (df["Z"] != "")] # The A value is not in the column if it doesn't change so we need to fill down - df['A'] = df['A'].ffill() + df["A"] = df["A"].ffill() elif self.year == 2020: # The column headers and units are repeated in the 2020 table - df = df[(df['A'] != 'A') & (df['Z'] != 'Z')] + df = df[(df["A"] != "A") & (df["Z"] != "Z")] # Repeated column heading also means we have to cast to create new columns df["TableYear"] = self.year df["N"] = pd.to_numeric(df["A"]) - pd.to_numeric(df["Z"]) df["Symbol"] = pd.to_numeric(df["Z"]).map(self.z_to_symbol) - - return df.astype(self._data_types()) except ValueError as e: print(f"Parsing error: {e}") + + return df.astype(self._data_types()) diff --git a/nuclearmasses/element_converter.py b/nuclearmasses/element_converter.py index 5e4f989..4a07eb3 100644 --- a/nuclearmasses/element_converter.py +++ b/nuclearmasses/element_converter.py @@ -7,8 +7,10 @@ class ElementConverter: TODO: Create accessor function that do some argument validation """ - def __init__(self): + def __init__(self) -> None: """Construct the symbol -> Z and Z -> symbol dictionaries.""" + # fmt: off + # Fromatter wants to put each item on it's own line, I don't self.z_to_symbol: dict[int, str] = { 0: "n", 1: "H", 2: "He", 3: "Li", 4: "Be", 5: "B", 6: "C", 7: "N", 8: "O", 9: "F", 10: "Ne", 11: "Na", 12: "Mg", 13: "Al", 14: "Si", 15: "P", 16: "S", 17: "Cl", 18: "Ar", 19: "K", @@ -20,9 +22,10 @@ def __init__(self): 70: "Yb", 71: "Lu", 72: "Hf", 73: "Ta", 74: "W", 75: "Re", 76: "Os", 77: "Ir", 78: "Pt", 79: "Au", 80: "Hg", 81: "Tl", 82: "Pb", 83: "Bi", 84: "Po", 85: "At", 86: "Rn", 87: "Fr", 88: "Ra", 89: "Ac", 90: "Th", 91: "Pa", 92: "U", 93: "Np", 94: "Pu", 95: "Am", 96: "Cm", 97: "Bk", 98: "Cf", 99: "Es", - 100: "Fm", 101: "Md", 102: "No", 103: "Lr", 104: "Rf", 105: "Db", 106: "Sg", 107: "Bh", 108: "Hs", 109: "Mt", + 100: "Fm", 101: "Md", 102: "No", 103: "Lr", 104: "Rf", 105: "Db", 106: "Sg", 107: "Bh", 108: "Hs", 109: "Mt", # noqa: E501 110: "Ds", 111: "Rg", 112: "Cn", 113: "Ed", 114: "Fl", 115: "Ef", 116: "Lv", 117: "Ts", 118: "Og" } + # fmt: on # Switch the keys and values of the z_to_symbol dictionary so a user can access the Z value using the symbol self.symbol_to_z: dict[str, int] = {val: key for key, val in self.z_to_symbol.items()} diff --git a/nuclearmasses/mass_table.py b/nuclearmasses/mass_table.py index c258c10..0e430e3 100644 --- a/nuclearmasses/mass_table.py +++ b/nuclearmasses/mass_table.py @@ -1,5 +1,4 @@ import importlib.resources -import logging import pathlib import pandas as pd @@ -93,18 +92,16 @@ def _parse_ame_data(self, year: int) -> pd.DataFrame: ame_mass_df = AMEMassParser(ame_mass, year).read_file() # Merge all 3 of the AME files/data frames into one - common_columns = ['A', 'Z', 'N', 'TableYear', 'Symbol'] + common_columns = ["A", "Z", "N", "TableYear", "Symbol"] temp_df = ame_mass_df.merge(AMEReactionParserOne(ame_reaction_1, year).read_file(), on=common_columns) return temp_df.merge(AMEReactionParserTwo(ame_reaction_2, year).read_file(), on=common_columns) def _combine_all_data(self) -> pd.DataFrame: """Combine all NUBASE and AME data into a single pandas DataFrame.""" - common_columns = ['A', 'Z', 'N', 'TableYear', 'Symbol'] - df = pd.merge(self.ame, self.nubase, on=common_columns, how='outer') + common_columns = ["A", "Z", "N", "TableYear", "Symbol"] + df = pd.merge(self.ame, self.nubase, on=common_columns, how="outer") - df["NUBASERelativeError"] = abs( - df["NUBASEMassExcessError"] / df["NUBASEMassExcess"] - ) + df["NUBASERelativeError"] = abs(df["NUBASEMassExcessError"] / df["NUBASEMassExcess"]) df["AMERelativeError"] = abs(df["AMEMassExcessError"] / df["AMEMassExcess"]) # 12C has a 0.0 +/ 0.0 mass excess by definition so calculating relative error -> NaN @@ -113,7 +110,7 @@ def _combine_all_data(self) -> pd.DataFrame: df.loc[(df.Symbol == "C") & (df.A == 12), "AMERelativeError"] = 0.0 # 198Au has a typo in it's decay mode in the 2012 table. It is recorded as '-' - df.loc[(df.A == 198) & (df.Z == 79) & (df.TableYear == 2012), 'Decay'] = "B-" + df.loc[(df.A == 198) & (df.Z == 79) & (df.TableYear == 2012), "Decay"] = "B-" return df diff --git a/nuclearmasses/nubase_file.py b/nuclearmasses/nubase_file.py index 7c922b7..904806d 100644 --- a/nuclearmasses/nubase_file.py +++ b/nuclearmasses/nubase_file.py @@ -130,19 +130,19 @@ def __init__(self, year: int): self.END_DECAYSTRING = None self.column_limits = [ - (self.START_A, self.END_A), - (self.START_Z, self.END_Z), - (self.START_STATE, self.END_STATE), - (self.START_ME, self.END_ME), - (self.START_DME, self.END_DME), - (self.START_ISOMER, self.END_ISOMER), - (self.START_DISOMER, self.END_DISOMER), - (self.START_HALFLIFEVALUE, self.END_HALFLIFEVALUE), - (self.START_HALFLIFEUNIT, self.END_HALFLIFEUNIT), - (self.START_HALFLIFEERROR, self.END_HALFLIFEERROR), - (self.START_SPIN, self.END_SPIN), - (self.START_DECAYSTRING, self.END_DECAYSTRING), - ] + (self.START_A, self.END_A), + (self.START_Z, self.END_Z), + (self.START_STATE, self.END_STATE), + (self.START_ME, self.END_ME), + (self.START_DME, self.END_DME), + (self.START_ISOMER, self.END_ISOMER), + (self.START_DISOMER, self.END_DISOMER), + (self.START_HALFLIFEVALUE, self.END_HALFLIFEVALUE), + (self.START_HALFLIFEUNIT, self.END_HALFLIFEUNIT), + (self.START_HALFLIFEERROR, self.END_HALFLIFEERROR), + (self.START_SPIN, self.END_SPIN), + (self.START_DECAYSTRING, self.END_DECAYSTRING), + ] if year > 2003: self.column_limits.insert(-1, (self.START_YEAR, self.END_YEAR)) diff --git a/nuclearmasses/nubase_parse.py b/nuclearmasses/nubase_parse.py index 3a45f86..61cfc96 100644 --- a/nuclearmasses/nubase_parse.py +++ b/nuclearmasses/nubase_parse.py @@ -1,6 +1,8 @@ """Extract the data from the nubase file.""" + import logging import pathlib +import typing import pandas as pd @@ -25,102 +27,102 @@ def _column_names(self) -> list[str]: match self.year: case 1995 | 2003: return [ - "A", - "Z", - "State", - "NUBASEMassExcess", - "NUBASEMassExcessError", - "IsomerEnergy", - "IsomerEnergyError", - "HalfLifeValue", - "HalfLifeUnit", - "HalfLifeError", - "Spin", - "DecayModes", - ] + "A", + "Z", + "State", + "NUBASEMassExcess", + "NUBASEMassExcessError", + "IsomerEnergy", + "IsomerEnergyError", + "HalfLifeValue", + "HalfLifeUnit", + "HalfLifeError", + "Spin", + "DecayModes", + ] case _: return [ - "A", - "Z", - "State", - "NUBASEMassExcess", - "NUBASEMassExcessError", - "IsomerEnergy", - "IsomerEnergyError", - "HalfLifeValue", - "HalfLifeUnit", - "HalfLifeError", - "Spin", - "DiscoveryYear", - "DecayModes", - ] + "A", + "Z", + "State", + "NUBASEMassExcess", + "NUBASEMassExcessError", + "IsomerEnergy", + "IsomerEnergyError", + "HalfLifeValue", + "HalfLifeUnit", + "HalfLifeError", + "Spin", + "DiscoveryYear", + "DecayModes", + ] def _data_types(self) -> dict: """Set the data type depending on the year""" match self.year: case 1995 | 2003: return { - "Symbol": "string", - "A": "Int64", - "Z": "Int64", - "N": "Int64", - "Experimental": "boolean", - # "State": "Int64", - "NUBASEMassExcess": "float64", - "NUBASEMassExcessError": "float64", - # "IsomerEnergy": "float64", - # "IsomerEnergyError": "float64", - "HalfLifeValue": "float64", - "HalfLifeUnit": "string", - "HalfLifeError": "float64", - "Spin": "string", - "DecayModes": "string", - } + "Symbol": "string", + "A": "Int64", + "Z": "Int64", + "N": "Int64", + "Experimental": "boolean", + # "State": "Int64", + "NUBASEMassExcess": "float64", + "NUBASEMassExcessError": "float64", + # "IsomerEnergy": "float64", + # "IsomerEnergyError": "float64", + "HalfLifeValue": "float64", + "HalfLifeUnit": "string", + "HalfLifeError": "float64", + "Spin": "string", + "DecayModes": "string", + } case _: return { - "Symbol": "string", - "A": "Int64", - "Z": "Int64", - "N": "Int64", - "Experimental": "boolean", - # "State": "Int64", - "NUBASEMassExcess": "float64", - "NUBASEMassExcessError": "float64", - # "IsomerEnergy": "float64", - # "IsomerEnergyError": "float64", - "HalfLifeValue": "float64", - "HalfLifeUnit": "string", - "HalfLifeError": "float64", - "Spin": "string", - "DiscoveryYear": "Int64", - "DecayModes": "string", - } + "Symbol": "string", + "A": "Int64", + "Z": "Int64", + "N": "Int64", + "Experimental": "boolean", + # "State": "Int64", + "NUBASEMassExcess": "float64", + "NUBASEMassExcessError": "float64", + # "IsomerEnergy": "float64", + # "IsomerEnergyError": "float64", + "HalfLifeValue": "float64", + "HalfLifeUnit": "string", + "HalfLifeError": "float64", + "Spin": "string", + "DiscoveryYear": "Int64", + "DecayModes": "string", + } def _na_values(self) -> dict: """Set the columns that have placeholder values""" match self.year: case 1995: return { - "NUBASEMassExcess": [''], - "NUBASEMassExcessError": [''], - "State": [''], - "HalfLifeValue": [''], - "HalfLifeUnit": [''], - "HalfLifeError": [''], - "Spin": [''], - "DecayModes": [''], - } + "NUBASEMassExcess": [""], + "NUBASEMassExcessError": [""], + "State": [""], + "HalfLifeValue": [""], + "HalfLifeUnit": [""], + "HalfLifeError": [""], + "Spin": [""], + "DecayModes": [""], + } case _: return { - "State": [''], - "NUBASEMassExcess": [''], - "NUBASEMassExcessError": [''], - "HalfLifeValue": ['', 'p-unst', 'p-unst#'], - "HalfLifeUnit": [''], - "HalfLifeError": [''], - "DiscoveryYear": [''], - "DecayModes": [''], - } + "State": [""], + "NUBASEMassExcess": [""], + "NUBASEMassExcessError": [""], + "HalfLifeValue": ["", "p-unst", "p-unst#"], + "HalfLifeUnit": [""], + "HalfLifeError": [""], + "DiscoveryYear": [""], + "DecayModes": [""], + } def read_file(self) -> pd.DataFrame: """Read the file using it's known format @@ -131,17 +133,17 @@ def read_file(self) -> pd.DataFrame: """ try: df = pd.read_fwf( - self.filename, - colspecs=self.column_limits, - names=self._column_names(), - na_values=self._na_values(), - keep_default_na=False, - on_bad_lines='warn', - skiprows=self.HEADER, - skipfooter=self.FOOTER - ) + self.filename, + colspecs=typing.cast(typing.Sequence[tuple[int, int]], self.column_limits), # appease mypy + names=self._column_names(), + na_values=self._na_values(), + keep_default_na=False, + on_bad_lines="warn", + skiprows=self.HEADER, + skipfooter=self.FOOTER, + ) # We use the NUBASE data to define whether or not an isotope is experimentally measured, - df['Experimental'] = ~df["NUBASEMassExcess"].astype("string").str.contains('#', na=False) + df["Experimental"] = ~df["NUBASEMassExcess"].astype("string").str.contains("#", na=False) # Once we have used the '#' to determine if it's experimental or not, we can remove all instances of it df.replace("#", "", regex=True, inplace=True) @@ -151,15 +153,16 @@ def read_file(self) -> pd.DataFrame: # For the moment, we will ignore anything this is not the ground state df = df[df["State"] == 0] # As 'State' is now necessarily 0 and the Isomer columns are empty, drop them. - df = df.drop(columns=['State', 'IsomerEnergy', 'IsomerEnergyError']) + df = df.drop(columns=["State", "IsomerEnergy", "IsomerEnergyError"]) # Convert stable isotopes into ones with enormous lifetimes with zero error so we can cast - df.loc[df['HalfLifeValue'] == 'stbl', ['HalfLifeValue', 'HalfLifeUnit', 'HalfLifeError']] = [99.99, 'Zy', 0.0] + mask = df["HalfLifeValue"] == "stbl" + df.loc[mask, ["HalfLifeValue", "HalfLifeUnit", "HalfLifeError"]] = (99.99, "Zy", 0.0) - df['HalfLifeValue'] = df['HalfLifeValue'].astype("string").str.replace(r'[<>?~]','', regex=True) + df["HalfLifeValue"] = df["HalfLifeValue"].astype("string").str.replace(r"[<>?~]", "", regex=True) # We'll be lazy here and remove any characters in this column. Future us will parse this properly - df['HalfLifeError'] = df['HalfLifeError'].astype("string").str.replace(r'[<>?~a-z]','', regex=True) - - return df.astype(self._data_types()) + df["HalfLifeError"] = df["HalfLifeError"].astype("string").str.replace(r"[<>?~a-z]", "", regex=True) except ValueError as e: print(f"Parsing error: {e}") + + return df.astype(self._data_types()) diff --git a/pyproject.toml b/pyproject.toml index 730031f..8c6f774 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,8 @@ keywords = [ [project.optional-dependencies] dev = [ "coverage", + "mypy", + "pandas-stubs", ] [project.urls] @@ -70,3 +72,30 @@ nuclearmasses = [ omit = [ "tests/*" ] + +[tool.isort] +known_first_party = ["nuclearmasses"] + +[tool.ruff] +line-length = 120 + +[tool.ruff.format] +# Nothing different from defaults + +[tool.ruff.lint.isort] +known-first-party = ["nuclearmasses"] +force-sort-within-sections = true + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "E", # pycodestyle errors + "F", # pyflakes + "W", # pycodestyle warnings + "I", # isort + "UP", # pyupgrade +] + +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["E501"] diff --git a/tests/test_ame_mass_parse.py b/tests/test_ame_mass_parse.py index 26af634..78b492c 100644 --- a/tests/test_ame_mass_parse.py +++ b/tests/test_ame_mass_parse.py @@ -1,60 +1,69 @@ -from nuclearmasses.ame_mass_parse import AMEMassParser - import io + import pandas as pd import pandas.testing as pdt +from nuclearmasses.ame_mass_parse import AMEMassParser + def test_1983_mass(): # 67Fe was randomly selected to test the AME mass parsing. According to AME it didn't exist in 1983 so will use 67Ni - line = io.StringIO("0 11 39 28 67 Ni +n2p -63742.471 19.056 582618.683 19.066 B- 3560.871 20.646 66 931570.167 20.457 -.0") + line = io.StringIO( + "0 11 39 28 67 Ni +n2p -63742.471 19.056 582618.683 19.066 B- 3560.871 20.646 66 931570.167 20.457 -.0" + ) parser = AMEMassParser(line, 1983) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1983], - 'Symbol': ['Ni'], - 'A': [67], - 'Z': [28], - 'N': [39], - 'AMEMassExcess': [-63742.471], - 'AMEMassExcessError': [19.056], - 'BindingEnergyPerA': [582618.683/67], - 'BindingEnergyPerAError': [19.066/67], - 'BetaDecayEnergy': [3560.871], - 'BetaDecayEnergyError': [20.646], - 'AtomicMass': [66.931579167], - 'AtomicMassError': [20.457/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [1983], + "Symbol": ["Ni"], + "A": [67], + "Z": [28], + "N": [39], + "AMEMassExcess": [-63742.471], + "AMEMassExcessError": [19.056], + "BindingEnergyPerA": [582618.683 / 67], + "BindingEnergyPerAError": [19.066 / 67], + "BetaDecayEnergy": [3560.871], + "BetaDecayEnergyError": [20.646], + "AtomicMass": [66.931579167], + "AtomicMassError": [20.457 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_1993_mass(): - line = io.StringIO("0 15 41 26 67 Fe x -46574.693 465.747 567012.139 465.747 B- 8746.727 543.150 66 950000.000 500.000") + line = io.StringIO( + "0 15 41 26 67 Fe x -46574.693 465.747 567012.139 465.747 B- 8746.727 543.150 66 950000.000 500.000" + ) parser = AMEMassParser(line, 1993) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1993], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-46574.693], - 'AMEMassExcessError': [465.747], - 'BindingEnergyPerA': [567012.133/67], - 'BindingEnergyPerAError': [465.747/67], - 'BetaDecayEnergy': [8746.727], - 'BetaDecayEnergyError': [543.150], - 'AtomicMass': [66.950000000], - 'AtomicMassError': [500.0/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [1993], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-46574.693], + "AMEMassExcessError": [465.747], + "BindingEnergyPerA": [567012.133 / 67], + "BindingEnergyPerAError": [465.747 / 67], + "BetaDecayEnergy": [8746.727], + "BetaDecayEnergyError": [543.150], + "AtomicMass": [66.950000000], + "AtomicMassError": [500.0 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) @@ -62,135 +71,155 @@ def test_1993_mass(): def test_1995_mass(): # Yes the 1995 line is identical to the 1993 line - line = io.StringIO(" 15 41 26 67 Fe x -46574.693 465.747 567012.133 465.747 B- 8746.727 543.150 66 950000.000 500.000") + line = io.StringIO( + " 15 41 26 67 Fe x -46574.693 465.747 567012.133 465.747 B- 8746.727 543.150 66 950000.000 500.000" + ) parser = AMEMassParser(line, 1995) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1995], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-46574.693], - 'AMEMassExcessError': [465.747], - 'BindingEnergyPerA': [567012.133/67], - 'BindingEnergyPerAError': [465.747/67], - 'BetaDecayEnergy': [8746.727], - 'BetaDecayEnergyError': [543.150], - 'AtomicMass': [66.950000000], - 'AtomicMassError': [500.0/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [1995], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-46574.693], + "AMEMassExcessError": [465.747], + "BindingEnergyPerA": [567012.133 / 67], + "BindingEnergyPerAError": [465.747 / 67], + "BetaDecayEnergy": [8746.727], + "BetaDecayEnergyError": [543.150], + "AtomicMass": [66.950000000], + "AtomicMassError": [500.0 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2003_mass(): - line = io.StringIO(" 15 41 26 67 Fe x -45692.348 415.570 8449.695 6.203 B- 9368.702 523.438 66 950947.244 446.132") + line = io.StringIO( + " 15 41 26 67 Fe x -45692.348 415.570 8449.695 6.203 B- 9368.702 523.438 66 950947.244 446.132" + ) parser = AMEMassParser(line, 2003) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2003], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-45692.348], - 'AMEMassExcessError': [415.570], - 'BindingEnergyPerA': [8449.695], - 'BindingEnergyPerAError': [6.203], - 'BetaDecayEnergy': [9368.702], - 'BetaDecayEnergyError': [523.438], - 'AtomicMass': [66.950947244], - 'AtomicMassError': [446.132/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [2003], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-45692.348], + "AMEMassExcessError": [415.570], + "BindingEnergyPerA": [8449.695], + "BindingEnergyPerAError": [6.203], + "BetaDecayEnergy": [9368.702], + "BetaDecayEnergyError": [523.438], + "AtomicMass": [66.950947244], + "AtomicMassError": [446.132 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2012_mass(): - line = io.StringIO(" 15 41 26 67 Fe x -46068.530 217.972 8455.310 3.253 B- 9253.245 218.067 66 950543.395 234.002") + line = io.StringIO( + " 15 41 26 67 Fe x -46068.530 217.972 8455.310 3.253 B- 9253.245 218.067 66 950543.395 234.002" + ) parser = AMEMassParser(line, 2012) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2012], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-46068.530], - 'AMEMassExcessError': [217.972], - 'BindingEnergyPerA': [8455.310], - 'BindingEnergyPerAError': [3.253], - 'BetaDecayEnergy': [9253.245], - 'BetaDecayEnergyError': [218.067], - 'AtomicMass': [66.950543395], - 'AtomicMassError': [234.002/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [2012], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-46068.530], + "AMEMassExcessError": [217.972], + "BindingEnergyPerA": [8455.310], + "BindingEnergyPerAError": [3.253], + "BetaDecayEnergy": [9253.245], + "BetaDecayEnergyError": [218.067], + "AtomicMass": [66.950543395], + "AtomicMassError": [234.002 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2016_mass(): - line = io.StringIO(" 15 41 26 67 Fe x -45610.155 270.285 8448.469 4.034 B- 9711.620 270.362 66 951035.482 290.163") + line = io.StringIO( + " 15 41 26 67 Fe x -45610.155 270.285 8448.469 4.034 B- 9711.620 270.362 66 951035.482 290.163" + ) parser = AMEMassParser(line, 2016) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2016], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-45610.155], - 'AMEMassExcessError': [270.285], - 'BindingEnergyPerA': [8448.469], - 'BindingEnergyPerAError': [4.034], - 'BetaDecayEnergy': [9711.620], - 'BetaDecayEnergyError': [270.362], - 'AtomicMass': [66.951035482], - 'AtomicMassError': [290.163/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [2016], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-45610.155], + "AMEMassExcessError": [270.285], + "BindingEnergyPerA": [8448.469], + "BindingEnergyPerAError": [4.034], + "BetaDecayEnergy": [9711.620], + "BetaDecayEnergyError": [270.362], + "AtomicMass": [66.951035482], + "AtomicMassError": [290.163 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2020_mass(): - line = io.StringIO(" 15 41 26 67 Fe x -45708.416 3.819 8449.9359 0.0570 B- 9613.3678 7.4900 66 950930.000 4.100") + line = io.StringIO( + " 15 41 26 67 Fe x -45708.416 3.819 8449.9359 0.0570 B- 9613.3678 7.4900 66 950930.000 4.100" + ) parser = AMEMassParser(line, 2020) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2020], - 'Symbol': ['Fe'], - 'A': [67], - 'Z': [26], - 'N': [41], - 'AMEMassExcess': [-45708.416], - 'AMEMassExcessError': [3.819], - 'BindingEnergyPerA': [8449.9359], - 'BindingEnergyPerAError': [0.0570], - 'BetaDecayEnergy': [9613.3678], - 'BetaDecayEnergyError': [7.4900], - 'AtomicMass': [66.950930], - 'AtomicMassError': [4.100/1.0e6], - }) + expected = pd.DataFrame( + { + "TableYear": [2020], + "Symbol": ["Fe"], + "A": [67], + "Z": [26], + "N": [41], + "AMEMassExcess": [-45708.416], + "AMEMassExcessError": [3.819], + "BindingEnergyPerA": [8449.9359], + "BindingEnergyPerAError": [0.0570], + "BetaDecayEnergy": [9613.3678], + "BetaDecayEnergyError": [7.4900], + "AtomicMass": [66.950930], + "AtomicMassError": [4.100 / 1.0e6], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) diff --git a/tests/test_ame_reaction_1_parse.py b/tests/test_ame_reaction_1_parse.py index 0568d62..ab3b950 100644 --- a/tests/test_ame_reaction_1_parse.py +++ b/tests/test_ame_reaction_1_parse.py @@ -1,224 +1,253 @@ -from nuclearmasses.ame_reaction_1_parse import AMEReactionParserOne - import io + import pandas as pd import pandas.testing as pdt +from nuclearmasses.ame_reaction_1_parse import AMEReactionParserOne + def test_1983_rct1(): # We are cheating a little here because this line does not have the A value in the file # To test properly either choose a different isotope or read from the first instance with A so it gets populated - line = io.StringIO(" 186 Ir 77 15780 250 9536 20 3850 100 -7600# 300# -2639 20 -10640# 200#") + line = io.StringIO( + " 186 Ir 77 15780 250 9536 20 3850 100 -7600# 300# -2639 20 -10640# 200#" + ) parser = AMEReactionParserOne(line, 1983) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1983], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15780], - 'TwoNeutronSeparationEnergyError': [250], - 'TwoProtonSeparationEnergy': [9536], - 'TwoProtonSeparationEnergyError': [20], - 'QAlpha': [3850], - 'QAlphaError': [100], - 'QTwoBeta': [-7600], - 'QTwoBetaError': [300], - 'QEpsilon': [-2639], - 'QEpsilonError': [20], - 'QBetaNeutron': [-10640], - 'QBetaNeutronError': [200], - }) + expected = pd.DataFrame( + { + "TableYear": [1983], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15780], + "TwoNeutronSeparationEnergyError": [250], + "TwoProtonSeparationEnergy": [9536], + "TwoProtonSeparationEnergyError": [20], + "QAlpha": [3850], + "QAlphaError": [100], + "QTwoBeta": [-7600], + "QTwoBetaError": [300], + "QEpsilon": [-2639], + "QEpsilonError": [20], + "QBetaNeutron": [-10640], + "QBetaNeutronError": [200], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_1993_rct1(): - line = io.StringIO(" 186 Ir 77 15618.44 270.74 9522.98 20.49 3852.98 103.94 -7419.61 145.57 -2635.85 20.03 -10622# 230#") + line = io.StringIO( + " 186 Ir 77 15618.44 270.74 9522.98 20.49 3852.98 103.94 -7419.61 145.57 -2635.85 20.03 -10622# 230#" + ) parser = AMEReactionParserOne(line, 1993) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1993], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15618.44], - 'TwoNeutronSeparationEnergyError': [270.74], - 'TwoProtonSeparationEnergy': [9522.89], - 'TwoProtonSeparationEnergyError': [20.49], - 'QAlpha': [3852.98], - 'QAlphaError': [103.94], - 'QTwoBeta': [-7419.61], - 'QTwoBetaError': [145.57], - 'QEpsilon': [-2635.85], - 'QEpsilonError': [20.03], - 'QBetaNeutron': [-10622], - 'QBetaNeutronError': [230], - }) + expected = pd.DataFrame( + { + "TableYear": [1993], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15618.44], + "TwoNeutronSeparationEnergyError": [270.74], + "TwoProtonSeparationEnergy": [9522.89], + "TwoProtonSeparationEnergyError": [20.49], + "QAlpha": [3852.98], + "QAlphaError": [103.94], + "QTwoBeta": [-7419.61], + "QTwoBetaError": [145.57], + "QEpsilon": [-2635.85], + "QEpsilonError": [20.03], + "QBetaNeutron": [-10622], + "QBetaNeutronError": [230], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_1995_rct1(): - line = io.StringIO(" 186 Ir 77 15618.41 270.74 9522.89 20.49 3853.04 103.94 -7495.33 145.56 -2635.83 20.03 -10682.00 207.60") + line = io.StringIO( + " 186 Ir 77 15618.41 270.74 9522.89 20.49 3853.04 103.94 -7495.33 145.56 -2635.83 20.03 -10682.00 207.60" + ) parser = AMEReactionParserOne(line, 1995) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1995], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15618.41], - 'TwoNeutronSeparationEnergyError': [270.74], - 'TwoProtonSeparationEnergy': [9522.89], - 'TwoProtonSeparationEnergyError': [20.49], - 'QAlpha': [3853.04], - 'QAlphaError': [103.94], - 'QTwoBeta': [-7495.33], - 'QTwoBetaError': [145.56], - 'QEpsilon': [-2635.83], - 'QEpsilonError': [20.03], - 'QBetaNeutron': [-10682.00], - 'QBetaNeutronError': [207.60], - }) + expected = pd.DataFrame( + { + "TableYear": [1995], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15618.41], + "TwoNeutronSeparationEnergyError": [270.74], + "TwoProtonSeparationEnergy": [9522.89], + "TwoProtonSeparationEnergyError": [20.49], + "QAlpha": [3853.04], + "QAlphaError": [103.94], + "QTwoBeta": [-7495.33], + "QTwoBetaError": [145.56], + "QEpsilon": [-2635.83], + "QEpsilonError": [20.03], + "QBetaNeutron": [-10682.00], + "QBetaNeutronError": [207.60], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2003_rct1(): - line = io.StringIO(" 186 Ir 77 15704.74 32.47 9524.26 17.08 3849.65 103.31 -7458.10 26.70 -2639.77 16.57 -10561.10 44.19") + line = io.StringIO( + " 186 Ir 77 15704.74 32.47 9524.26 17.08 3849.65 103.31 -7458.10 26.70 -2639.77 16.57 -10561.10 44.19" + ) parser = AMEReactionParserOne(line, 2003) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2003], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15704.74], - 'TwoNeutronSeparationEnergyError': [32.47], - 'TwoProtonSeparationEnergy': [9524.26], - 'TwoProtonSeparationEnergyError': [17.08], - 'QAlpha': [3849.65], - 'QAlphaError': [103.31], - 'QTwoBeta': [-7458.10], - 'QTwoBetaError': [26.70], - 'QEpsilon': [-2639.77], - 'QEpsilonError': [16.57], - 'QBetaNeutron': [-10561.10], - 'QBetaNeutronError': [44.19], - }) + expected = pd.DataFrame( + { + "TableYear": [2003], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15704.74], + "TwoNeutronSeparationEnergyError": [32.47], + "TwoProtonSeparationEnergy": [9524.26], + "TwoProtonSeparationEnergyError": [17.08], + "QAlpha": [3849.65], + "QAlphaError": [103.31], + "QTwoBeta": [-7458.10], + "QTwoBetaError": [26.70], + "QEpsilon": [-2639.77], + "QEpsilonError": [16.57], + "QBetaNeutron": [-10561.10], + "QBetaNeutronError": [44.19], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2012_rct1(): - line = io.StringIO(" 186 Ir 77 15706.55 32.47 9527.99 17.09 3848.03 103.31 -7459.92 26.70 -2641.13 16.57 -10557.95 30.67") + line = io.StringIO( + " 186 Ir 77 15706.55 32.47 9527.99 17.09 3848.03 103.31 -7459.92 26.70 -2641.13 16.57 -10557.95 30.67" + ) parser = AMEReactionParserOne(line, 2012) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2012], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15706.55], - 'TwoNeutronSeparationEnergyError': [32.47], - 'TwoProtonSeparationEnergy': [9527.99], - 'TwoProtonSeparationEnergyError': [17.09], - 'QAlpha': [3848.03], - 'QAlphaError': [103.31], - 'QTwoBeta': [-7459.92], - 'QTwoBetaError': [26.70], - 'QEpsilon': [-2641.13], - 'QEpsilonError': [16.57], - 'QBetaNeutron': [-10557.95], - 'QBetaNeutronError': [30.67], - }) + expected = pd.DataFrame( + { + "TableYear": [2012], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15706.55], + "TwoNeutronSeparationEnergyError": [32.47], + "TwoProtonSeparationEnergy": [9527.99], + "TwoProtonSeparationEnergyError": [17.09], + "QAlpha": [3848.03], + "QAlphaError": [103.31], + "QTwoBeta": [-7459.92], + "QTwoBetaError": [26.70], + "QEpsilon": [-2641.13], + "QEpsilonError": [16.57], + "QBetaNeutron": [-10557.95], + "QBetaNeutronError": [30.67], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2016_rct1(): - line = io.StringIO(" 186 Ir 77 15704.13 32.47 9530.65 17.07 3848.80 103.31 -7457.49 26.70 -2642.29 16.55 -10555.52 30.67") + line = io.StringIO( + " 186 Ir 77 15704.13 32.47 9530.65 17.07 3848.80 103.31 -7457.49 26.70 -2642.29 16.55 -10555.52 30.67" + ) parser = AMEReactionParserOne(line, 2016) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2016], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15704.13], - 'TwoNeutronSeparationEnergyError': [32.47], - 'TwoProtonSeparationEnergy': [9530.65], - 'TwoProtonSeparationEnergyError': [17.07], - 'QAlpha': [3848.80], - 'QAlphaError': [103.31], - 'QTwoBeta': [-7457.49], - 'QTwoBetaError': [26.70], - 'QEpsilon': [-2642.29], - 'QEpsilonError': [16.55], - 'QBetaNeutron': [-10555.52], - 'QBetaNeutronError': [30.67], - }) + expected = pd.DataFrame( + { + "TableYear": [2016], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15704.13], + "TwoNeutronSeparationEnergyError": [32.47], + "TwoProtonSeparationEnergy": [9530.65], + "TwoProtonSeparationEnergyError": [17.07], + "QAlpha": [3848.80], + "QAlphaError": [103.31], + "QTwoBeta": [-7457.49], + "QTwoBetaError": [26.70], + "QEpsilon": [-2642.29], + "QEpsilonError": [16.55], + "QBetaNeutron": [-10555.52], + "QBetaNeutronError": [30.67], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) def test_2020_rct1(): - line = io.StringIO(" 186 Ir 77 15704.1312 32.4655 9530.4731 17.0698 3848.8777 103.3133 -7457.4943 26.6968 -2642.2739 16.5459 -10555.5245 30.6658") + line = io.StringIO( + " 186 Ir 77 15704.1312 32.4655 9530.4731 17.0698 3848.8777 103.3133 -7457.4943 26.6968 -2642.2739 16.5459 -10555.5245 30.6658" + ) parser = AMEReactionParserOne(line, 2020) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2020], - 'Symbol': ['Ir'], - 'A': [186], - 'Z': [77], - 'N': [109], - 'TwoNeutronSeparationEnergy': [15704.1312], - 'TwoNeutronSeparationEnergyError': [32.4655], - 'TwoProtonSeparationEnergy': [9530.4731], - 'TwoProtonSeparationEnergyError': [17.0698], - 'QAlpha': [3848.8777], - 'QAlphaError': [103.3133], - 'QTwoBeta': [-7457.4943], - 'QTwoBetaError': [26.6968], - 'QEpsilon': [-2642.2739], - 'QEpsilonError': [16.5459], - 'QBetaNeutron': [-10555.5245], - 'QBetaNeutronError': [30.6658], - }) + expected = pd.DataFrame( + { + "TableYear": [2020], + "Symbol": ["Ir"], + "A": [186], + "Z": [77], + "N": [109], + "TwoNeutronSeparationEnergy": [15704.1312], + "TwoNeutronSeparationEnergyError": [32.4655], + "TwoProtonSeparationEnergy": [9530.4731], + "TwoProtonSeparationEnergyError": [17.0698], + "QAlpha": [3848.8777], + "QAlphaError": [103.3133], + "QTwoBeta": [-7457.4943], + "QTwoBetaError": [26.6968], + "QEpsilon": [-2642.2739], + "QEpsilonError": [16.5459], + "QBetaNeutron": [-10555.5245], + "QBetaNeutronError": [30.6658], + } + ) expected = expected.astype(parser._data_types()) pdt.assert_frame_equal(df, expected, check_like=True) diff --git a/tests/test_ame_reaction_2_parse.py b/tests/test_ame_reaction_2_parse.py index e2537bb..c0427bc 100644 --- a/tests/test_ame_reaction_2_parse.py +++ b/tests/test_ame_reaction_2_parse.py @@ -1,36 +1,41 @@ -from nuclearmasses.ame_reaction_2_parse import AMEReactionParserTwo - import io + import pandas as pd import pandas.testing as pdt +from nuclearmasses.ame_reaction_2_parse import AMEReactionParserTwo + def test_1983_rct2(): - line = io.StringIO(" 204 Tl 81 7853 17 5702.8 1.7 -13480 120 12613.7 1.8 8608.4 1.8 7180 50") + line = io.StringIO( + " 204 Tl 81 7853 17 5702.8 1.7 -13480 120 12613.7 1.8 8608.4 1.8 7180 50" + ) parser = AMEReactionParserTwo(line, 1983) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1983], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [7853], - 'OneNeutronSeparationEnergyError': [17], - 'OneProtonSeparationEnergy': [5702.8], - 'OneProtonSeparationEnergyError': [1.7], - 'QFourBeta': [-13480], - 'QFourBetaError': [120], - 'QDeuteronAlpha': [12613.7], - 'QDeuteronAlphaError': [1.8], - 'QProtonAlpha': [8608.4], - 'QProtonAlphaError': [1.8], - 'QNeutronAlpha': [7180], - 'QNeutronAlphaError': [50], - }) + expected = pd.DataFrame( + { + "TableYear": [1983], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [7853], + "OneNeutronSeparationEnergyError": [17], + "OneProtonSeparationEnergy": [5702.8], + "OneProtonSeparationEnergyError": [1.7], + "QFourBeta": [-13480], + "QFourBetaError": [120], + "QDeuteronAlpha": [12613.7], + "QDeuteronAlphaError": [1.8], + "QProtonAlpha": [8608.4], + "QProtonAlphaError": [1.8], + "QNeutronAlpha": [7180], + "QNeutronAlphaError": [50], + } + ) expected = expected.astype(parser._data_types()) @@ -38,31 +43,35 @@ def test_1983_rct2(): def test_1993_rct2(): - line = io.StringIO(" 204 Tl 81 6655.82 0.29 6365.32 1.26 -12492.85 71.39 13712.87 1.23 8183.14 1.25 7690.59 15.05") + line = io.StringIO( + " 204 Tl 81 6655.82 0.29 6365.32 1.26 -12492.85 71.39 13712.87 1.23 8183.14 1.25 7690.59 15.05" + ) parser = AMEReactionParserTwo(line, 1993) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1993], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6655.86], - 'OneNeutronSeparationEnergyError': [0.29], - 'OneProtonSeparationEnergy': [6365.35], - 'OneProtonSeparationEnergyError': [1.26], - 'QFourBeta': [-12492.85], - 'QFourBetaError': [71.39], - 'QDeuteronAlpha': [13712.87], - 'QDeuteronAlphaError': [1.23], - 'QProtonAlpha': [8183.14], - 'QProtonAlphaError': [1.25], - 'QNeutronAlpha': [7690.59], - 'QNeutronAlphaError': [15.05], - }) + expected = pd.DataFrame( + { + "TableYear": [1993], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6655.86], + "OneNeutronSeparationEnergyError": [0.29], + "OneProtonSeparationEnergy": [6365.35], + "OneProtonSeparationEnergyError": [1.26], + "QFourBeta": [-12492.85], + "QFourBetaError": [71.39], + "QDeuteronAlpha": [13712.87], + "QDeuteronAlphaError": [1.23], + "QProtonAlpha": [8183.14], + "QProtonAlphaError": [1.25], + "QNeutronAlpha": [7690.59], + "QNeutronAlphaError": [15.05], + } + ) expected = expected.astype(parser._data_types()) @@ -70,31 +79,35 @@ def test_1993_rct2(): def test_1995_rct2(): - line = io.StringIO(" 204 Tl 81 6655.86 0.29 6365.35 1.26 -12494.05 92.85 13713.05 1.23 8183.32 1.24 7702.97 3.35") + line = io.StringIO( + " 204 Tl 81 6655.86 0.29 6365.35 1.26 -12494.05 92.85 13713.05 1.23 8183.32 1.24 7702.97 3.35" + ) parser = AMEReactionParserTwo(line, 1995) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1995], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6655.86], - 'OneNeutronSeparationEnergyError': [0.29], - 'OneProtonSeparationEnergy': [6365.35], - 'OneProtonSeparationEnergyError': [1.26], - 'QFourBeta': [-12494.05], - 'QFourBetaError': [92.85], - 'QDeuteronAlpha': [13713.05], - 'QDeuteronAlphaError': [1.23], - 'QProtonAlpha': [8183.32], - 'QProtonAlphaError': [1.24], - 'QNeutronAlpha': [7702.97], - 'QNeutronAlphaError': [3.35], - }) + expected = pd.DataFrame( + { + "TableYear": [1995], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6655.86], + "OneNeutronSeparationEnergyError": [0.29], + "OneProtonSeparationEnergy": [6365.35], + "OneProtonSeparationEnergyError": [1.26], + "QFourBeta": [-12494.05], + "QFourBetaError": [92.85], + "QDeuteronAlpha": [13713.05], + "QDeuteronAlphaError": [1.23], + "QProtonAlpha": [8183.32], + "QProtonAlphaError": [1.24], + "QNeutronAlpha": [7702.97], + "QNeutronAlphaError": [3.35], + } + ) expected = expected.astype(parser._data_types()) @@ -102,31 +115,35 @@ def test_1995_rct2(): def test_2003_rct2(): - line = io.StringIO(" 204 Tl 81 6656.10 0.29 6365.82 1.25 -12470.66 24.01 13710.69 1.15 8181.34 1.16 7701.54 3.34") + line = io.StringIO( + " 204 Tl 81 6656.10 0.29 6365.82 1.25 -12470.66 24.01 13710.69 1.15 8181.34 1.16 7701.54 3.34" + ) parser = AMEReactionParserTwo(line, 2003) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2003], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6656.10], - 'OneNeutronSeparationEnergyError': [0.29], - 'OneProtonSeparationEnergy': [6365.82], - 'OneProtonSeparationEnergyError': [1.25], - 'QFourBeta': [-12470.66], - 'QFourBetaError': [24.01], - 'QDeuteronAlpha': [13710.69], - 'QDeuteronAlphaError': [1.15], - 'QProtonAlpha': [8181.34], - 'QProtonAlphaError': [1.16], - 'QNeutronAlpha': [7701.54], - 'QNeutronAlphaError': [3.34], - }) + expected = pd.DataFrame( + { + "TableYear": [2003], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6656.10], + "OneNeutronSeparationEnergyError": [0.29], + "OneProtonSeparationEnergy": [6365.82], + "OneProtonSeparationEnergyError": [1.25], + "QFourBeta": [-12470.66], + "QFourBetaError": [24.01], + "QDeuteronAlpha": [13710.69], + "QDeuteronAlphaError": [1.15], + "QProtonAlpha": [8181.34], + "QProtonAlphaError": [1.16], + "QNeutronAlpha": [7701.54], + "QNeutronAlphaError": [3.34], + } + ) expected = expected.astype(parser._data_types()) @@ -134,31 +151,35 @@ def test_2003_rct2(): def test_2012_rct2(): - line = io.StringIO(" 204 Tl 81 6656.09 0.29 6365.80 1.25 -12470.19 22.31 13710.68 1.14 8181.16 1.15 7701.67 3.33") + line = io.StringIO( + " 204 Tl 81 6656.09 0.29 6365.80 1.25 -12470.19 22.31 13710.68 1.14 8181.16 1.15 7701.67 3.33" + ) parser = AMEReactionParserTwo(line, 2012) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2012], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6656.09], - 'OneNeutronSeparationEnergyError': [0.29], - 'OneProtonSeparationEnergy': [6365.80], - 'OneProtonSeparationEnergyError': [1.25], - 'QFourBeta': [-12470.19], - 'QFourBetaError': [22.31], - 'QDeuteronAlpha': [13710.68], - 'QDeuteronAlphaError': [1.14], - 'QProtonAlpha': [8181.16], - 'QProtonAlphaError': [1.15], - 'QNeutronAlpha': [7701.67], - 'QNeutronAlphaError': [3.33], - }) + expected = pd.DataFrame( + { + "TableYear": [2012], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6656.09], + "OneNeutronSeparationEnergyError": [0.29], + "OneProtonSeparationEnergy": [6365.80], + "OneProtonSeparationEnergyError": [1.25], + "QFourBeta": [-12470.19], + "QFourBetaError": [22.31], + "QDeuteronAlpha": [13710.68], + "QDeuteronAlphaError": [1.14], + "QProtonAlpha": [8181.16], + "QProtonAlphaError": [1.15], + "QNeutronAlpha": [7701.67], + "QNeutronAlphaError": [3.33], + } + ) expected = expected.astype(parser._data_types()) @@ -166,31 +187,35 @@ def test_2012_rct2(): def test_2016_rct2(): - line = io.StringIO(" 204 Tl 81 6656.08 0.29 6365.85 1.25 -12470.71 22.32 13709.99 1.06 8180.45 1.07 7700.97 3.31") + line = io.StringIO( + " 204 Tl 81 6656.08 0.29 6365.85 1.25 -12470.71 22.32 13709.99 1.06 8180.45 1.07 7700.97 3.31" + ) parser = AMEReactionParserTwo(line, 2016) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2016], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6656.08], - 'OneNeutronSeparationEnergyError': [0.29], - 'OneProtonSeparationEnergy': [6365.85], - 'OneProtonSeparationEnergyError': [1.25], - 'QFourBeta': [-12470.71], - 'QFourBetaError': [22.32], - 'QDeuteronAlpha': [13709.99], - 'QDeuteronAlphaError': [1.06], - 'QProtonAlpha': [8180.45], - 'QProtonAlphaError': [1.07], - 'QNeutronAlpha': [7700.97], - 'QNeutronAlphaError': [3.31], - }) + expected = pd.DataFrame( + { + "TableYear": [2016], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6656.08], + "OneNeutronSeparationEnergyError": [0.29], + "OneProtonSeparationEnergy": [6365.85], + "OneProtonSeparationEnergyError": [1.25], + "QFourBeta": [-12470.71], + "QFourBetaError": [22.32], + "QDeuteronAlpha": [13709.99], + "QDeuteronAlphaError": [1.06], + "QProtonAlpha": [8180.45], + "QProtonAlphaError": [1.07], + "QNeutronAlpha": [7700.97], + "QNeutronAlphaError": [3.31], + } + ) expected = expected.astype(parser._data_types()) @@ -198,31 +223,35 @@ def test_2016_rct2(): def test_2020_rct2(): - line = io.StringIO(" 204 Tl 81 6656.0787 0.2907 6365.8379 1.2542 -12470.8182 22.6974 13710.0469 1.0612 8180.5147 1.0721 7701.0380 3.3084") + line = io.StringIO( + " 204 Tl 81 6656.0787 0.2907 6365.8379 1.2542 -12470.8182 22.6974 13710.0469 1.0612 8180.5147 1.0721 7701.0380 3.3084" + ) parser = AMEReactionParserTwo(line, 2020) parser.HEADER = 0 parser.FOOTER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2020], - 'Symbol': ['Tl'], - 'A': [204], - 'Z': [81], - 'N': [123], - 'OneNeutronSeparationEnergy': [6656.0787], - 'OneNeutronSeparationEnergyError': [0.2907], - 'OneProtonSeparationEnergy': [6365.8379], - 'OneProtonSeparationEnergyError': [1.2542], - 'QFourBeta': [-12470.8182], - 'QFourBetaError': [22.6974], - 'QDeuteronAlpha': [13710.0469], - 'QDeuteronAlphaError': [1.0612], - 'QProtonAlpha': [8180.5147], - 'QProtonAlphaError': [1.0721], - 'QNeutronAlpha': [7701.0380], - 'QNeutronAlphaError': [3.3084], - }) + expected = pd.DataFrame( + { + "TableYear": [2020], + "Symbol": ["Tl"], + "A": [204], + "Z": [81], + "N": [123], + "OneNeutronSeparationEnergy": [6656.0787], + "OneNeutronSeparationEnergyError": [0.2907], + "OneProtonSeparationEnergy": [6365.8379], + "OneProtonSeparationEnergyError": [1.2542], + "QFourBeta": [-12470.8182], + "QFourBetaError": [22.6974], + "QDeuteronAlpha": [13710.0469], + "QDeuteronAlphaError": [1.0612], + "QProtonAlpha": [8180.5147], + "QProtonAlphaError": [1.0721], + "QNeutronAlpha": [7701.0380], + "QNeutronAlphaError": [3.3084], + } + ) expected = expected.astype(parser._data_types()) diff --git a/tests/test_nubase_parse.py b/tests/test_nubase_parse.py index c3f595f..31bd10f 100644 --- a/tests/test_nubase_parse.py +++ b/tests/test_nubase_parse.py @@ -1,30 +1,35 @@ -from nuclearmasses.nubase_parse import NUBASEParser - import io + import pandas as pd import pandas.testing as pdt +from nuclearmasses.nubase_parse import NUBASEParser + def test_1995_nubase(): - line = io.StringIO("168 0670 168Ho -60085 29 2.99 m 0.07 3+ 94 B-=100") + line = io.StringIO( + "168 0670 168Ho -60085 29 2.99 m 0.07 3+ 94 B-=100" + ) parser = NUBASEParser(line, 1995) df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [1995], - 'Experimental': [True], - 'Symbol': ['Ho'], - 'A': [168], - 'Z': [67], - 'N': [101], - 'NUBASEMassExcess': [-60085], - 'NUBASEMassExcessError': [29], - 'HalfLifeValue': [2.99], - 'HalfLifeUnit': ['m'], - 'HalfLifeError': [0.07], - 'Spin': ['3+'], - 'DecayModes': ['B-=100'], - }) + expected = pd.DataFrame( + { + "TableYear": [1995], + "Experimental": [True], + "Symbol": ["Ho"], + "A": [168], + "Z": [67], + "N": [101], + "NUBASEMassExcess": [-60085], + "NUBASEMassExcessError": [29], + "HalfLifeValue": [2.99], + "HalfLifeUnit": ["m"], + "HalfLifeError": [0.07], + "Spin": ["3+"], + "DecayModes": ["B-=100"], + } + ) expected = expected.astype(parser._data_types()) @@ -32,25 +37,29 @@ def test_1995_nubase(): def test_2003_nubase(): - line = io.StringIO("168 0670 168Ho -60070 30 2.99 m 0.07 3+ 94 B-=100") + line = io.StringIO( + "168 0670 168Ho -60070 30 2.99 m 0.07 3+ 94 B-=100" + ) parser = NUBASEParser(line, 2003) df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2003], - 'Experimental': [True], - 'Symbol': ['Ho'], - 'A': [168], - 'Z': [67], - 'N': [101], - 'NUBASEMassExcess': [-60070], - 'NUBASEMassExcessError': [30], - 'HalfLifeValue': [2.99], - 'HalfLifeUnit': ['m'], - 'HalfLifeError': [0.07], - 'Spin': ['3+'], - 'DecayModes': ['B-=100'], - }) + expected = pd.DataFrame( + { + "TableYear": [2003], + "Experimental": [True], + "Symbol": ["Ho"], + "A": [168], + "Z": [67], + "N": [101], + "NUBASEMassExcess": [-60070], + "NUBASEMassExcessError": [30], + "HalfLifeValue": [2.99], + "HalfLifeUnit": ["m"], + "HalfLifeError": [0.07], + "Spin": ["3+"], + "DecayModes": ["B-=100"], + } + ) expected = expected.astype(parser._data_types()) @@ -58,26 +67,30 @@ def test_2003_nubase(): def test_2012_nubase(): - line = io.StringIO("168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100") + line = io.StringIO( + "168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100" + ) parser = NUBASEParser(line, 2012) df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2012], - 'Experimental': [True], - 'Symbol': ['Ho'], - 'A': [168], - 'Z': [67], - 'N': [101], - 'NUBASEMassExcess': [-60060], - 'NUBASEMassExcessError': [30], - 'HalfLifeValue': [2.99], - 'HalfLifeUnit': ['m'], - 'HalfLifeError': [0.07], - 'Spin': ['3+'], - 'DiscoveryYear': [1960], - 'DecayModes': ['B-=100'], - }) + expected = pd.DataFrame( + { + "TableYear": [2012], + "Experimental": [True], + "Symbol": ["Ho"], + "A": [168], + "Z": [67], + "N": [101], + "NUBASEMassExcess": [-60060], + "NUBASEMassExcessError": [30], + "HalfLifeValue": [2.99], + "HalfLifeUnit": ["m"], + "HalfLifeError": [0.07], + "Spin": ["3+"], + "DiscoveryYear": [1960], + "DecayModes": ["B-=100"], + } + ) expected = expected.astype(parser._data_types()) @@ -85,26 +98,30 @@ def test_2012_nubase(): def test_2016_nubase(): - line = io.StringIO("168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100") + line = io.StringIO( + "168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100" + ) parser = NUBASEParser(line, 2016) df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2016], - 'Experimental': [True], - 'Symbol': ['Ho'], - 'A': [168], - 'Z': [67], - 'N': [101], - 'NUBASEMassExcess': [-60060], - 'NUBASEMassExcessError': [30], - 'HalfLifeValue': [2.99], - 'HalfLifeUnit': ['m'], - 'HalfLifeError': [0.07], - 'Spin': ['3+'], - 'DiscoveryYear': [1960], - 'DecayModes': ['B-=100'], - }) + expected = pd.DataFrame( + { + "TableYear": [2016], + "Experimental": [True], + "Symbol": ["Ho"], + "A": [168], + "Z": [67], + "N": [101], + "NUBASEMassExcess": [-60060], + "NUBASEMassExcessError": [30], + "HalfLifeValue": [2.99], + "HalfLifeUnit": ["m"], + "HalfLifeError": [0.07], + "Spin": ["3+"], + "DiscoveryYear": [1960], + "DecayModes": ["B-=100"], + } + ) expected = expected.astype(parser._data_types()) @@ -112,27 +129,31 @@ def test_2016_nubase(): def test_2020_nubase(): - line = io.StringIO("168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100") + line = io.StringIO( + "168 0670 168Ho -60060 30 2.99 m 0.07 3+ 10 1960 B-=100" + ) parser = NUBASEParser(line, 2020) parser.HEADER = 0 df = parser.read_file() - expected = pd.DataFrame({ - 'TableYear': [2020], - 'Experimental': [True], - 'Symbol': ['Ho'], - 'A': [168], - 'Z': [67], - 'N': [101], - 'NUBASEMassExcess': [-60060], - 'NUBASEMassExcessError': [30], - 'HalfLifeValue': [2.99], - 'HalfLifeUnit': ['m'], - 'HalfLifeError': [0.07], - 'Spin': ['3+'], - 'DiscoveryYear': [1960], - 'DecayModes': ['B-=100'], - }) + expected = pd.DataFrame( + { + "TableYear": [2020], + "Experimental": [True], + "Symbol": ["Ho"], + "A": [168], + "Z": [67], + "N": [101], + "NUBASEMassExcess": [-60060], + "NUBASEMassExcessError": [30], + "HalfLifeValue": [2.99], + "HalfLifeUnit": ["m"], + "HalfLifeError": [0.07], + "Spin": ["3+"], + "DiscoveryYear": [1960], + "DecayModes": ["B-=100"], + } + ) expected = expected.astype(parser._data_types()) diff --git a/tests/test_parse.py b/tests/test_parse.py index 37f457a..16d9f1c 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -15,4 +15,3 @@ def test_symbol_to_Z(): assert converter.symbol_to_z["Al"] == 13 assert converter.symbol_to_z["Fe"] == 26 assert converter.symbol_to_z["Po"] == 84 -