Source code for MagmaPEC.error_propagation.MC_parameters

from collections import OrderedDict
from typing import Dict, Union

import MagmaPandas as mp
import numpy as np
import pandas as pd
from MagmaPandas.Fe_redox.Fe3Fe2_models import Fe3Fe2_models_dict
from MagmaPandas.Kd.Ol_melt.FeMg import Kd_olmelt_FeMg_models_dict

from MagmaPEC import model_configuration
from MagmaPEC.error_propagation.FeOi_error_propagation import FeOi_prediction

# TODO add links to extra information about Fe3Fe2 and Kd error estimates.


[docs] class PEC_MC_parameters: """ Class for fetching parameters for PEC Monte Carlo simulations. Includes error propagation for: - melt composition - olivine composition - initial MI FeO content - melt |Fe3Fe2| ratios - olivine-melt Fe-Mg partition coefficients. Parameters ---------- melt_errors : pandas Series, None one standard deviation errors on melt compositions in oxide wt. %. Errors are 0 when set to None. Default value: None olivine_errors : pandas Series, None one standard deviation errors on olivine compositions in oxide wt. %. Errors are 0 when set to None. Default value: None FeOi_errors : float, pandas Series, :py:class:`~MagmaPEC.error_propagation.FeOi_prediction` errors on melt initial FeO content. float or Series for errors on FeO, FeOi_prediction for errors on coefficients of linear regressions of FeO against melt major element compositions. Default value: 0.0 Fe3Fe2 : bool propagate melt |Fe3Fe2| errors. Errors are calculated from regressions on a validation dataset. Default value: False Kd : bool propagate olivine-melt Fe-Mg partition coefficient errors. Errors are calibration errors as reported in their respective publications. Default value: False Attributes ---------- parameters : OrderedDict dictionary with errors ordered as 'melt', 'olivine', 'pressure', 'FeOi', 'Fe3Fe2', 'Kd', 'temperature' """ parameters = OrderedDict() def __init__( self, melt_errors: None | pd.Series | pd.DataFrame | np.ndarray = None, olivine_errors: None | pd.Series | pd.DataFrame | np.ndarray = None, pressure_errors: pd.Series | np.ndarray | int | float = 0.0, FeOi_errors: float | int | FeOi_prediction = 0.0, Fe3Fe2: bool = False, Kd: bool = False, temperature: bool = False, ): for val, name in zip((melt_errors, olivine_errors), ("melt", "olivine")): if (val is not None) & ( not isinstance(val, (pd.Series, pd.DataFrame, np.ndarray)) ): raise TypeError( f"{name} errors need to be None, Series, DataFrame or Array" ) if (pressure_errors is not None) & ( not isinstance(pressure_errors, (pd.Series, np.ndarray, float, int)) ): raise TypeError( f"{name} errors need to be None, Series, Array, float, or int" ) self.melt_errors = melt_errors self.olivine_errors = olivine_errors self.pressure_errors = pressure_errors self.FeOi_errors = FeOi_errors self.Fe3Fe2 = Fe3Fe2 self.Kd = Kd self.temperature = temperature
[docs] def get_parameters(self, n: int): """ Randomly sample parameter errors. Results are stored in ``parameters``. melt, olivine and FeOi errors are calculated based on user input values. |Fe3Fe2| and Kd errors are in standard deviations and calculated based on model calibration errors. Parameters ---------- n : int amount of random samples. """ # melt if self.melt_errors is None: self.parameters["melt"] = np.repeat(0.0, n) else: self.parameters["melt"] = np.random.normal( loc=0, scale=self.melt_errors, size=(n, *self.melt_errors.shape) ) # olivine if self.olivine_errors is None: self.parameters["olivine"] = np.repeat(0.0, n) else: self.parameters["olivine"] = np.random.normal( loc=0, scale=self.olivine_errors, size=(n, *self.olivine_errors.shape) ) if isinstance(self.pressure_errors, (float, int)): self.parameters["pressure"] = np.random.normal( loc=0, scale=self.pressure_errors, size=n ) else: self.parameters["pressure"] = np.random.normal( loc=0, scale=self.pressure_errors, size=(n, *self.pressure_errors.shape) ) # FeOi if isinstance(self.FeOi_errors, (float, int)): self.parameters["FeOi"] = np.random.normal( loc=0, scale=self.FeOi_errors, size=n ) elif isinstance(self.FeOi_errors, (pd.Series, np.ndarray)): self.parameters["FeOi"] = np.random.normal( loc=0, scale=self.FeOi_errors, size=(n, *self.FeOi_errors.shape) ) elif isinstance(self.FeOi_errors, FeOi_prediction): self.parameters["FeOi"] = self.FeOi_errors.random_sample_coefficients(n=n) for param in ["Fe3Fe2", "Kd", "temperature"]: if getattr(self, param): self.parameters[param] = np.random.normal(loc=0, scale=1, size=n) else: self.parameters[param] = np.repeat(0.0, n)
# # Fe3Fe2 # if self.Fe3Fe2: # self.parameters["Fe3Fe2"] = Fe3Fe2_model.get_offset_parameters(n=n) # else: # self.parameters["Fe3Fe2"] = np.repeat(0.0, n) # # Kd # if self.Kd: # self.parameters["Kd"] = Kd_model.get_offset_parameters(n=n) # else: # self.parameters["Kd"] = np.repeat(0.0, n) def _get_iterators(self): return [ i.iterrows() if isinstance(i, pd.DataFrame) else i for i in self.parameters.values() ]