Source code for VESIcal.core

"""
Single Source of Truth pattern for oxide-cation compositional factors.
All derived data structures are computed from a single master dictionary.
"""

# Master data structure - single source of truth
oxide_data = {
    'SiO2': {
        'mass': 60.083,
        'cation': 'Si',
        'cation_num': 1,
        'oxygen_num': 2,
        'cation_charge': 4,
        'cation_mass': 28.085,
        'groups': ['magmasat', 'anhydrous']
    },
    'TiO2': {
        'mass': 79.867,
        'cation': 'Ti',
        'cation_num': 1,
        'oxygen_num': 2,
        'cation_charge': 4,
        'cation_mass': 47.867,
        'groups': ['magmasat', 'anhydrous']
    },
    'Al2O3': {
        'mass': 101.961,
        'cation': 'Al',
        'cation_num': 2,
        'oxygen_num': 3,
        'cation_charge': 3,
        'cation_mass': 26.982,
        'groups': ['magmasat', 'anhydrous']
    },
    'Cr2O3': {
        'mass': 151.992,
        'cation': 'Cr',
        'cation_num': 2,
        'oxygen_num': 3,
        'cation_charge': 3,
        'cation_mass': 51.996,
        'groups': ['magmasat', 'anhydrous']
    },
    'FeO': {
        'mass': 71.844,
        'cation': 'Fe',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 55.845,
        'groups': ['magmasat', 'anhydrous']
    },
    'Fe2O3': {
        'mass': 159.687,
        'cation': 'Fe3',
        'cation_num': 2,
        'oxygen_num': 3,
        'cation_charge': 3,
        'cation_mass': 55.845,
        'groups': ['magmasat', 'anhydrous']
    },
    'MnO': {
        'mass': 70.937,
        'cation': 'Mn',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 54.938,
        'groups': ['magmasat', 'anhydrous']
    },
    'MgO': {
        'mass': 40.304,
        'cation': 'Mg',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 24.305,
        'groups': ['magmasat', 'anhydrous']
    },
    'CaO': {
        'mass': 56.077,
        'cation': 'Ca',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 40.078,
        'groups': ['magmasat', 'anhydrous']
    },
    'Na2O': {
        'mass': 61.979,
        'cation': 'Na',
        'cation_num': 2,
        'oxygen_num': 1,
        'cation_charge': 1,
        'cation_mass': 22.990,
        'groups': ['magmasat', 'anhydrous']
    },
    'K2O': {
        'mass': 94.195,
        'cation': 'K',
        'cation_num': 2,
        'oxygen_num': 1,
        'cation_charge': 1,
        'cation_mass': 39.098,
        'groups': ['magmasat', 'anhydrous']
    },
    'P2O5': {
        'mass': 141.943,
        'cation': 'P',
        'cation_num': 2,
        'oxygen_num': 5,
        'cation_charge': 5,
        'cation_mass': 30.974,
        'groups': ['magmasat', 'anhydrous']
    },
    'NiO': {
        'mass': 74.692,
        'cation': 'Ni',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 58.693,
        'groups': ['magmasat', 'anhydrous']
    },
    'CoO': {
        'mass': 44.01,
        'cation': 'Co',
        'cation_num': 1,
        'oxygen_num': 1,
        'cation_charge': 2,
        'cation_mass': 28.01,
        'groups': ['magmasat', 'anhydrous']
    },
    'H2O': {
        'mass': 18.02,
        'cation': 'H',
        'cation_num': 2,
        'oxygen_num': 1,
        'cation_charge': 1,
        'cation_mass': 1.01,
        'groups': ['magmasat', 'volatile']
    },
    'CO2': {
        'mass': 44.01,
        'cation': 'C',
        'cation_num': 1,
        'oxygen_num': 2,
        'cation_charge': 4,
        'cation_mass': 12.011,
        'groups': ['magmasat', 'volatile']
    },
    'F2O': {
        'mass': 37.997,
        'cation': 'F',
        'cation_num': 2,
        'oxygen_num': 1,
        'cation_charge': 1,
        'cation_mass': 18.998,
        'groups': ['anhydrous']
    }
}

# Derived data structures - all computed from oxide_data
# Lists
oxides = list(oxide_data.keys())
cations = list(set(data['cation'] for data in oxide_data.values()))
magmasat_oxides = [oxide for oxide, data in oxide_data.items() if 'magmasat' in data['groups']]
anhydrous_oxides = [oxide for oxide, data in oxide_data.items() if 'anhydrous' in data['groups']]
volatiles = [oxide for oxide, data in oxide_data.items() if 'volatile' in data['groups']]

# Property dictionaries
oxideMass = {oxide: data['mass'] for oxide, data in oxide_data.items()}
CationNum = {oxide: data['cation_num'] for oxide, data in oxide_data.items()}
OxygenNum = {oxide: data['oxygen_num'] for oxide, data in oxide_data.items()}
CationCharge = {oxide: data['cation_charge'] for oxide, data in oxide_data.items()}
CationMass = {oxide: data['cation_mass'] for oxide, data in oxide_data.items()}

# Conversion mappings
oxides_to_cations = {oxide: data['cation'] for oxide, data in oxide_data.items()}
cations_to_oxides = {data['cation']: oxide for oxide, data in oxide_data.items()}


# ---------- DATA TRANSFORMATION FOR PANDAS DATAFRAMES --------- #
[docs] def fluid_molfrac_to_wt(data, H2O_colname='XH2O_fl_VESIcal', CO2_colname='XCO2_fl_VESIcal'): """ Takes in a pandas dataframe object and converts only the fluid composition from mole fraction to wt%, leaving the melt composition in tact. The user must specify the names of the XH2O_fl and XCO2_fl columns. Parameters ---------- data: pandas DataFrame Sample composition(s) containing columns for H2O and CO2 concentrations in the fluid. H2O_colname: str OPTIONAL. The default value is 'XH2O_fl', which is what is returned by BatchFile() core calculations. String containing the name of the column corresponding to the H2O concentration in the fluid, in mol fraction. CO2_colname: str OPTIONAL. The default value is 'XCO2_fl', which is what is returned by BatchFile() core calculations. String containing the name of the column corresponding to the CO2 concentration in the fluid, in mol fraction. Returns ------- pandas DataFrame Original data passed plus newly calculated values are returned. """ convData = data.copy() MPO_H2O_list = [] MPO_CO2_list = [] for index, row in convData.iterrows(): MPO_H2O_list.append(row[H2O_colname] * oxideMass["H2O"]) MPO_CO2_list.append(row[CO2_colname] * oxideMass["CO2"]) convData["MPO_H2O"] = MPO_H2O_list convData["MPO_CO2"] = MPO_CO2_list convData["H2O_fl_wt"] = 100 * convData["MPO_H2O"] / (convData["MPO_H2O"] + convData["MPO_CO2"]) convData["CO2_fl_wt"] = 100 * convData["MPO_CO2"] / (convData["MPO_H2O"] + convData["MPO_CO2"]) del convData["MPO_H2O"] del convData["MPO_CO2"] return convData
[docs] def fluid_wt_to_molfrac(data, H2O_colname='H2O_fl_wt', CO2_colname='CO2_fl_wt'): """ Takes in a pandas dataframe object and converts only the fluid composition from wt% to mole fraction, leaving the melt composition in tact. The user must specify the names of the H2O_fl_wt and CO2_fl_wt columns. Parameters ---------- data: pandas DataFrame DataFrame containing columns for H2O and CO2 concentrations in the fluid. H2O_colname: str OPTIONAL. The default value is 'H2O_fl_wt', which is what is returned by BatchFile() core calculations. String containing the name of the column corresponding to the H2O concentration in the fluid, in wt%. CO2_colname: str OPTIONAL. The default value is 'CO2_fl_wt', which is what is returned by BatchFile() core calculations. String containing the name of the column corresponding to the CO2 concentration in the fluid, in wt%. Returns ------- pandas DataFrame Original data passed plus newly calculated values are returned. """ convData = data.copy() MPO_H2O_list = [] MPO_CO2_list = [] for index, row in convData.iterrows(): MPO_H2O_list.append(row[H2O_colname] / oxideMass["H2O"]) MPO_CO2_list.append(row[CO2_colname] / oxideMass["CO2"]) convData["MPO_H2O"] = MPO_H2O_list convData["MPO_CO2"] = MPO_CO2_list convData["XH2O_fl"] = convData["MPO_H2O"] / (convData["MPO_H2O"] + convData["MPO_CO2"]) convData["XCO2_fl"] = convData["MPO_CO2"] / (convData["MPO_H2O"] + convData["MPO_CO2"]) del convData["MPO_H2O"] del convData["MPO_CO2"] return convData
class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, message): self.message = message class SaturationError(Error): """Exception raised for errors thrown when a sample does not reach saturation. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, message): self.message = message