def calculate_dissolved_volatiles(self, temperature, pressure, X_fluid=1, print_status=True, model='MagmaSat', record_errors=False, **kwargs): """ Calculates the amount of H2O and CO2 dissolved in a magma at the given P/T conditions and fluid composition. Fluid composition will be matched to within 0.0001 mole fraction. Parameters ---------- temperature: float, int, or str Temperature, in degrees C. Can be passed as float, in which case the passed value is used as the temperature for all samples. Alternatively, temperature information for each individual sample may already be present in the BatchFile object. If so, pass the str value corresponding to the column title in the BatchFile object. presure: float, int, or str Pressure, in bars. Can be passed as float or int, in which case the passed value is used as the pressure for all samples. Alternatively, pressure information for each individual sample may already be present in the BatchFile object. If so, pass the str value corresponding to the column title in the BatchFile object. X_fluid: float, int, or str OPTIONAL: Default value is 1. The mole fraction of H2O in the H2O-CO2 fluid. X_fluid=1 is a pure H2O fluid. X_fluid=0 is a pure CO2 fluid. Can be passed as a float or int, in which case the passed value is used as the X_fluid for all samples. Alternatively, X_fluid information for each individual sample may already be present in the BatchFile object. If so, pass the str value corresponding to the column title in the BatchFile object. print_status: bool OPTIONAL: The default value is True, in which case the progress of the calculation will be printed to the terminal. If set to False, nothing will be printed. MagmaSat calculations tend to be slow, and so a value of True is recommended for most use cases. model: string OPTIONAL: Default is 'MagmaSat'. Any other model name can be passed here. record_errors: bool OPTIONAL: If True, any errors arising during the calculation will be recorded as a column. Returns ------- pandas DataFrame Original data passed plus newly calculated values are returned. """ dissolved_data = self.get_data().copy() if isinstance(temperature, str): file_has_temp = True temp_name = temperature elif isinstance(temperature, float) or isinstance(temperature, int): file_has_temp = False else: raise core.InputError("temp must be type str or float or int") if isinstance(pressure, str): file_has_press = True press_name = pressure elif isinstance(pressure, float) or isinstance(pressure, int): file_has_press = False else: raise core.InputError("pressure must be type str or float or int") if isinstance(X_fluid, str): file_has_X = True X_name = X_fluid elif isinstance(X_fluid, float) or isinstance(X_fluid, int): file_has_X = False if X_fluid != 0 and X_fluid !=1: if X_fluid < 0.001 or X_fluid > 0.999: raise core.InputError("X_fluid is calculated to a precision of 0.0001 mole fraction. \ Value for X_fluid must be between 0.0001 and 0.9999.") else: raise core.InputError("X_fluid must be type str or float or int") # Check if the model passed as the attribute "model_type" # Currently only implemented for MagmaSat type models if hasattr(model, 'model_type') is True: model = model.model_type H2Ovals = [] CO2vals = [] warnings = [] errors = [] if model in models.get_model_names(model='mixed'): for index, row in dissolved_data.iterrows(): try: if file_has_temp == True: temperature = row[temp_name] if file_has_press == True: pressure = row[press_name] if file_has_X == True: X_fluid = row[X_name] # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) calc = calculate_classes.calculate_dissolved_volatiles(sample=bulk_comp, pressure=pressure, temperature=temperature, X_fluid=(X_fluid, 1-X_fluid), model=model, silence_warnings=True, **kwargs) H2Ovals.append(calc.result['H2O_liq']) CO2vals.append(calc.result['CO2_liq']) warnings.append(calc.calib_check) errors.append('') except Exception as inst: H2Ovals.append(np.nan) CO2vals.append(np.nan) warnings.append('Calculation Failed.') errors.append(sys.exc_info()[0]) dissolved_data["H2O_liq_VESIcal"] = H2Ovals dissolved_data["CO2_liq_VESIcal"] = CO2vals if file_has_temp == False: dissolved_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: dissolved_data["Pressure_bars_VESIcal"] = pressure if file_has_X == False: dissolved_data["X_fluid_input_VESIcal"] = X_fluid dissolved_data["Model"] = model dissolved_data["Warnings"] = warnings if record_errors == True: dissolved_data["Errors"] = errors return dissolved_data elif model == 'MagmaSat': XH2Ovals = [] XCO2vals = [] FluidProportionvals = [] iterno = 0 for index, row in dissolved_data.iterrows(): iterno += 1 if print_status == True: percent = iterno/len(dissolved_data.index) batchfile.status_bar.status_bar(percent, index) if file_has_temp == True: temperature = row[temp_name] if temperature <= 0: H2Ovals.append(np.nan) CO2vals.append(np.nan) XH2Ovals.append(np.nan) XCO2vals.append(np.nan) FluidProportionvals.append(np.nan) warnings.append("Sample skipped. Bad temperature.") errors.append(sys.exc_info()[0]) w.warn("Temperature for sample " + str(index) + " is <=0. Skipping sample.", stacklevel=2) if file_has_press == True: pressure = row[press_name] if temperature >0 and pressure <= 0: H2Ovals.append(np.nan) CO2vals.append(np.nan) XH2Ovals.append(np.nan) XCO2vals.append(np.nan) FluidProportionvals.append(np.nan) warnings.append("Sample skipped. Bad pressure.") errors.append(sys.exc_info()[0]) w.warn("Pressure for sample " + str(index) + " is <=0. Skipping sample.", stacklevel=2) if file_has_X == True: X_fluid = row[X_name] if temperature >0 and pressure >0 and X_fluid <0: H2Ovals.append(np.nan) CO2vals.append(np.nan) XH2Ovals.append(np.nan) XCO2vals.append(np.nan) FluidProportionvals.append(np.nan) warnings.append("Sample skipped. Bad X_fluid.") errors.append(sys.exc_info()[0]) w.warn("X_fluid for sample " + str(index) + " is <0. Skipping sample.", stacklevel=2) if temperature >0 and pressure >0 and X_fluid >1: H2Ovals.append(np.nan) CO2vals.append(np.nan) XH2Ovals.append(np.nan) XCO2vals.append(np.nan) FluidProportionvals.append(np.nan) warnings.append("Sample skipped. Bad X_fluid.") errors.append(sys.exc_info()[0]) w.warn("X_fluid for sample " + str(index) + " is >1. Skipping sample.", stacklevel=2) if temperature > 0 and pressure > 0 and X_fluid >=0 and X_fluid <=1: try: # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) calc = calculate_classes.calculate_dissolved_volatiles(sample=bulk_comp, pressure=pressure, temperature=temperature, X_fluid=X_fluid, model=model, silence_warnings=True, verbose=True) H2Ovals.append(calc.result['H2O_liq']) CO2vals.append(calc.result['CO2_liq']) XH2Ovals.append(calc.result['XH2O_fl']) XCO2vals.append(calc.result['XCO2_fl']) FluidProportionvals.append(calc.result['FluidProportion_wt']) warnings.append(calc.calib_check) errors.append('') except Exception as inst: H2Ovals.append(np.nan) CO2vals.append(np.nan) XH2Ovals.append(np.nan) XCO2vals.append(np.nan) FluidProportionvals.append(np.nan) warnings.append('Calculation Failed.') errors.append(sys.exc_info()[0]) dissolved_data["H2O_liq_VESIcal"] = H2Ovals dissolved_data["CO2_liq_VESIcal"] = CO2vals if file_has_temp == False: dissolved_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: dissolved_data["Pressure_bars_VESIcal"] = pressure if file_has_X == False: dissolved_data["X_fluid_input_VESIcal"] = X_fluid dissolved_data["Model"] = model dissolved_data["Warnings"] = warnings if record_errors == True: dissolved_data["Errors"] = errors return dissolved_data else: XH2Ovals = [] XCO2vals = [] FluidProportionvals = [] for index, row in dissolved_data.iterrows(): if file_has_temp == True: temperature = row[temp_name] if file_has_press == True: pressure = row[press_name] if file_has_X == True: X_fluid = row[X_name] # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) if 'Water' in model: try: calc = calculate_classes.calculate_dissolved_volatiles(sample=bulk_comp, pressure=pressure, temperature=temperature, X_fluid=X_fluid, model=model, silence_warnings=True) H2Ovals.append(calc.result) warnings.append(calc.calib_check) except: H2Ovals.append(0) warnings.append('Calculation Failed #001') if 'Carbon' in model: try: calc = calculate_classes.calculate_dissolved_volatiles(sample=bulk_comp, pressure=pressure, temperature=temperature, X_fluid=X_fluid, model=model, silence_warnings=True) CO2vals.append(calc.result) warnings.append(calc.calib_check) except: CO2vals.append(0) warnings.append('Calculation Failed #002') if 'Water' in model: dissolved_data["H2O_liq_VESIcal"] = H2Ovals if 'Carbon' in model: dissolved_data["CO2_liq_VESIcal"] = CO2vals if file_has_temp == False: dissolved_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: dissolved_data["Pressure_bars_VESIcal"] = pressure if file_has_X == False: dissolved_data["X_fluid_input_VESIcal"] = X_fluid dissolved_data["Model"] = model dissolved_data["Warnings"] = warnings return dissolved_data
def return_default_units(self, sample, calc_result, **kwargs): """ Checkes the default units set for the sample_class.Sample object and returns the result of a calculation in those units. Parameters ---------- sample: Sample class The rock composition as a Sample object. calc_result: dict or float Result of a calculate_dissolved_volatiles() calculation on a sample. """ default_units = sample.default_units # get the composition of bulk_comp = deepcopy(sample) # check if calculation result is H2O-only, CO2-only, or mixed # H2O-CO2 if isinstance(self.model_name, str): if self.model_name in models.get_model_names(model='mixed'): # set dissolved H2O and CO2 values. # this action assumes they are input as wt% but updates the # composition in its default units. bulk_comp.change_composition({ 'H2O': calc_result['H2O_liq'], 'CO2': calc_result['CO2_liq'] }) return { 'H2O_liq': bulk_comp.get_composition(species='H2O', units=default_units), 'CO2_liq': bulk_comp.get_composition(species='CO2', units=default_units) } elif 'Water' in self.model_name: bulk_comp.change_composition({'H2O': calc_result}) return bulk_comp.get_composition(species='H2O', units=default_units) elif 'Carbon' in self.model_name: bulk_comp.change_composition({'CO2': calc_result}) return bulk_comp.get_composition(species='CO2', units=default_units) elif self.model_name == 'MagmaSat': bulk_comp.change_composition({ 'H2O': calc_result['H2O_liq'], 'CO2': calc_result['CO2_liq'] }) # check if verbose method has been chosen if 'verbose' in kwargs and kwargs['verbose']: return { 'H2O_liq': bulk_comp.get_composition(species='H2O', units=default_units), 'CO2_liq': bulk_comp.get_composition(species='CO2', units=default_units), 'XH2O_fl': calc_result['XH2O_fl'], 'XCO2_fl': calc_result['XCO2_fl'], 'FluidProportion_wt': calc_result['FluidProportion_wt'] } else: return { 'H2O_liq': bulk_comp.get_composition(species='H2O', units=default_units), 'CO2_liq': bulk_comp.get_composition(species='CO2', units=default_units) } else: # if self.model_name is not a string, most likely this is a # user-created model class, and so we cannot interrogate it for # model type (H2O, CO2, or mixed). # TODO: create model type parameter so that we can ID model type # this way instead of via strings in a list! return calc_result
def calculate_equilibrium_fluid_comp(self, temperature, pressure=None, print_status=False, model='MagmaSat', **kwargs): """ Returns H2O and CO2 concentrations in wt% or mole fraction in a fluid in equilibrium with the given sample(s) at the given P/T condition. Parameters ---------- sample: BatchFile object Compositional information on samples in oxides. temperature: float, int, or str Temperature, in degrees C. Can be passed as float, in which case the passed value is used as the temperature for all samples. Alternatively, temperature information for each individual sample may already be present in the BatchFile object. If so, pass the str value corresponding to the column title in the BatchFile object. presure: float, int, or str Pressure, in bars. Can be passed as float or int, in which case the passed value is used as the pressure for all samples. Alternatively, pressure information for each individual sample may already be present in the BatchFile object. If so, pass the str value corresponding to the column title in the BatchFile object. model: string OPTIONAL: Default is 'MagmaSat'. Any other model name can be passed here. Returns ------- pandas DataFrame Original data passed plus newly calculated values are returned. """ fluid_data = self.get_data().copy() # Check if the model passed as the attribute "model_type" # Currently only implemented for MagmaSat type models if hasattr(model, 'model_type') is True: model = model.model_type if isinstance(temperature, str): file_has_temp = True temp_name = temperature elif isinstance(temperature, float) or isinstance(temperature, int): file_has_temp = False else: raise core.InputError("temp must be type str or float or int") if isinstance(pressure, str): file_has_press = True press_name = pressure elif isinstance(pressure, float) or isinstance(pressure, int) or type(pressure) == type(None): file_has_press = False else: raise core.InputError("pressure must be type str or float or int") H2Ovals = [] CO2vals = [] warnings = [] if model in models.get_model_names(model='mixed') or model == "MooreWater": for index, row in fluid_data.iterrows(): try: if file_has_temp == True: temperature = row[temp_name] if file_has_press == True: pressure = row[press_name] # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) calc = calculate_classes.calculate_equilibrium_fluid_comp(sample=bulk_comp, pressure=pressure, temperature=temperature, model=model, silence_warnings=True, **kwargs) H2Ovals.append(calc.result['H2O']) CO2vals.append(calc.result['CO2']) if calc.result['H2O'] == 0 and calc.result['CO2'] == 0: warnings.append(calc.calib_check + "Sample not saturated at these conditions") else: warnings.append(calc.calib_check) except: H2Ovals.append(np.nan) CO2vals.append(np.nan) warnings.append("Calculation Failed.") fluid_data["XH2O_fl_VESIcal"] = H2Ovals fluid_data["XCO2_fl_VESIcal"] = CO2vals if file_has_temp == False: fluid_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: fluid_data["Pressure_bars_VESIcal"] = pressure fluid_data["Model"] = model fluid_data["Warnings"] = warnings return fluid_data elif model == 'MagmaSat': iterno = 0 for index, row in fluid_data.iterrows(): iterno += 1 if print_status == True: percent = iterno/len(fluid_data.index) batchfile.status_bar.status_bar(percent, index) if file_has_temp == True: temperature = row[temp_name] if temperature <= 0: H2Ovals.append(np.nan) CO2vals.append(np.nan) warnings.append("Calculation skipped. Bad temperature.") w.warn("Temperature for sample " + str(index) + " is <=0. Skipping sample.", stacklevel=2) if file_has_press == True: pressure = row[press_name] if temperature >0 and pressure <= 0: H2Ovals.append(np.nan) CO2vals.append(np.nan) warnings.append("Calculation skipped. Bad pressure.") w.warn("Pressure for sample " + str(index) + " is <=0. Skipping sample.", stacklevel=2) if temperature > 0 and pressure > 0: try: # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) calc = calculate_classes.calculate_equilibrium_fluid_comp(sample=bulk_comp, pressure=pressure, temperature=temperature, model=model, silence_warnings=True) H2Ovals.append(calc.result['H2O']) CO2vals.append(calc.result['CO2']) if calc.result['H2O'] == 0 and calc.result['CO2'] == 0: warnings.append(calc.calib_check + "Sample not saturated at these conditions") else: warnings.append(calc.calib_check) except: H2Ovals.append(np.nan) CO2vals.append(np.nan) warnings.append("Calculation Failed.") fluid_data["XH2O_fl_VESIcal"] = H2Ovals fluid_data["XCO2_fl_VESIcal"] = CO2vals if file_has_temp == False: fluid_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: fluid_data["Pressure_bars_VESIcal"] = pressure fluid_data["Model"] = model fluid_data["Warnings"] = warnings return fluid_data else: saturated = [] for index, row in fluid_data.iterrows(): try: if file_has_temp == True: temperature = row[temp_name] if file_has_press == True: pressure = row[press_name] # Get sample comp as Sample class with defaults bulk_comp = self.get_sample_composition(index, normalization=self.default_normalization, units='wtpt_oxides', asSampleClass=True) bulk_comp.set_default_units(self.default_units) bulk_comp.set_default_normalization(self.default_normalization) calc = calculate_classes.calculate_equilibrium_fluid_comp(sample=bulk_comp, pressure=pressure, temperature=temperature, model=model, silence_warnings=True) saturated.append(calc.result) warnings.append(calc.calib_check) except: saturated.append(np.nan) warnings.append("Calculation Failed.") fluid_data["Saturated_VESIcal"] = saturated if file_has_temp == False: fluid_data["Temperature_C_VESIcal"] = temperature if file_has_press == False: fluid_data["Pressure_bars_VESIcal"] = pressure fluid_data["Model"] = model fluid_data["Warnings"] = warnings return fluid_data
def get_model_names(model='all'): return models.get_model_names(model=model)