def calculate_degassing_path(self, sample, temperature, pressure='saturation', fractionate_vapor=0.0, init_vapor=0.0, steps=50, **kwargs): """ Calculates degassing path for one sample Parameters ---------- sample: Sample class Magma major element composition. Legacy info follows, might still be useful? If pulling from an uploaded file with data for many samples, first call get_sample_composition() to get the sample desired. Then pass the result into this function. temperature: float Temperature at which to calculate degassing paths, in degrees C. pressure: float OPTIONAL. The perssure at which to begin the degassing calculations. Default value is 'saturation', which runs the calculation with the initial pressure at the saturation pressure. If a pressure greater than the saturation pressure is input, the calculation will start at saturation, since this is the first pressure at which any degassing will occur. fractionate_vapor: float OPTIONAL. Proportion of vapor removed at each pressure step. Default value is 0.0 (completely closed-system degassing). Specifies the type of calculation performed, either closed system (0.0) or open system (1.0) degassing. If any value between <1.0 is chosen, user can also specify the 'init_vapor' argument (see below). A value in between 0 and 1 will remove that proportion of vapor at each step. For example, for a value of 0.2, the calculation will remove 20% of the vapor and retain 80% of the vapor at each pressure step. init_vapor: float OPTIONAL. Default value is 0.0. Specifies the amount of vapor (in wt%) coexisting with the melt before degassing. steps: int OPTIONAL. Default value is 50. Specifies the number of steps in pressure space at which dissolved volatile concentrations are calculated. Returns ------- pandas DataFrame object """ sys.stdout.write("Finding saturation point... " ) # print start of calculation to terminal _sample = self.preprocess_sample(sample) # Normalize sample composition _normed_comp = _sample.get_composition(normalization='standard') _sample.change_composition(_normed_comp) _sample_dict = _sample.get_composition() # ------ RESET MELTS ------ # # MELTS needs to be reloaded here. If an unfeasible composition gets set inside of MELTS, # which can happen when running open-system degassing path calcs, the following calls to # MELTS will fail. This prevents that from happening. melts = equilibrate.MELTSmodel('1.2.0') # Suppress phases not required in the melts simulation phases = melts.get_phase_names() for phase in phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) melts.set_bulk_composition(_sample_dict) # ------------------------- # # Get saturation pressure data = self.calculate_saturation_pressure(sample=_sample, temperature=temperature, verbose=True) if pressure == 'saturation' or pressure >= data["SaturationP_bars"]: SatP_MPa = data["SaturationP_bars"] / 10.0 else: SatP_MPa = pressure / 10.0 # convert number of steps to step size MPa_step = SatP_MPa / steps if MPa_step < 1: MPa_step = 1 P_array = np.arange(1.0, SatP_MPa, MPa_step) P_array = -np.sort(-P_array) fl_wtper = data["FluidProportion_wt"] while fl_wtper <= init_vapor: output = melts.equilibrate_tp(temperature, SatP_MPa, initialize=True) (status, temperature, p, xmlout) = output[0] fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass + liq_mass) try: _sample_dict["H2O"] += fl_comp["H2O"] * 0.0005 except Exception: _sample_dict["H2O"] = _sample_dict["H2O"] * 1.1 try: _sample_dict["CO2"] += fl_comp["CO2"] * 0.0005 except Exception: _sample_dict["CO2"] = _sample_dict["CO2"] * 1.1 _sample = sample_class.Sample(_sample_dict) _sample_dict = _sample.get_composition(normalization='standard', units="wtpt_oxides") melts.set_bulk_composition(_sample_dict) # reset MELTS pressure = [] H2Oliq = [] CO2liq = [] H2Ofl = [] CO2fl = [] fluid_wtper = [] iterno = 0 sys.stdout.write( "\r") # carriage return to remove previous printed text for i in P_array: # Handle status_bar iterno += 1 percent = iterno / len(P_array) batchfile.status_bar.status_bar( percent, btext="Calculating degassing path...") fl_mass = 0.0 melts.set_bulk_composition(_sample_dict) output = melts.equilibrate_tp(temperature, i, initialize=True) (status, temperature, p, xmlout) = output[0] liq_comp = melts.get_composition_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid', mode='component') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass + liq_mass) if fl_mass > 0: pressure.append(p * 10.0) try: H2Oliq.append(liq_comp["H2O"]) except Exception: H2Oliq.append(0) try: CO2liq.append(liq_comp["CO2"]) except Exception: CO2liq.append(0) try: H2Ofl.append(fl_comp["Water"]) except Exception: H2Ofl.append(0) try: CO2fl.append(fl_comp["Carbon Dioxide"]) except Exception: CO2fl.append(0) fluid_wtper.append(fl_wtper) try: _sample_dict["H2O"] = ( liq_comp["H2O"] + (_sample_dict["H2O"] - liq_comp["H2O"]) * (1.0 - fractionate_vapor)) except Exception: _sample_dict["H2O"] = 0 try: _sample_dict["CO2"] = ( liq_comp["CO2"] + (_sample_dict["CO2"] - liq_comp["CO2"]) * (1.0 - fractionate_vapor)) except Exception: _sample_dict["CO2"] = 0 _sample = sample_class.Sample(_sample_dict) _sample_dict = _sample.get_composition(normalization='standard', units='wtpt_oxides') melts.set_bulk_composition( self.bulk_comp_orig) # this needs to be reset always! open_degassing_df = pd.DataFrame( list(zip(pressure, H2Oliq, CO2liq, H2Ofl, CO2fl, fluid_wtper)), columns=[ 'Pressure_bars', 'H2O_liq', 'CO2_liq', 'XH2O_fl', 'XCO2_fl', 'FluidProportion_wt' ]) open_degassing_df = open_degassing_df[ open_degassing_df.CO2_liq > 0.000001] open_degassing_df = open_degassing_df[ open_degassing_df.H2O_liq > 0.000001] return open_degassing_df
from VESIcal import core from VESIcal import models from VESIcal import sample_class from VESIcal import calculate_classes from VESIcal import batchfile import numpy as np import warnings as w import sys w.filterwarnings("ignore", message="rubicon.objc.ctypes_patch has only been tested ") # -------------- MELTS preamble --------------- # from thermoengine import equilibrate # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel('1.2.0') # Suppress phases not required in the melts simulation phases = melts.get_phase_names() for phase in phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) # --------------------------------------------- # # -------------- BATCH PROCESSING ----------- # class BatchFile(batchfile.BatchFile): """Performs model functions on a batchfile.BatchFile object """ pass def get_XH2O_fluid(self, sample, temperature, pressure, H2O, CO2): """An internally used function to calculate fluid composition.
def calculate_degassing_paths(self, sample, temp, system='closed', init_vapor='None'): """ Calculates degassing path for one sample Parameters ---------- sample: dict Dictionary with values for sample composition as oxides in wt%. If pulling from an uploaded file with data for many samples, first call get_sample_oxide_comp() to get the sample desired. Then pass the result into this function. temp: float Temperature at which to calculate degassing paths, in degrees C. system: str OPTIONAL. Default value is 'closed'. Specifies the type of calculation performed, either closed system or closed system degassing. If closed is chosen, user can also specify the 'init_vapor' argument (see below). Possible inputs are 'open' and 'closed'. init_vapor: float OPTIONAL. Default value is 0.0. Specifies the amount of vapor (in wt%) coexisting with the melt before degassing. Returns ------- pandas DataFrame object """ #--------------Preamble required for every MagmaSat method within Modeller---------------# # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel(self.model_version) # Suppress phases not required in the melts simulation self.oxides = melts.get_oxide_names() self.phases = melts.get_phase_names() for phase in self.phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) #---------------------------------------------------------------------------------------# sample = normalize(sample) bulk_comp_orig = sample feasible = melts.set_bulk_composition(sample) # Get saturation pressure data = self.calculate_saturation_pressure(sample, temp) if system == 'closed': if init_vapor == 'None': P_array = np.arange(1.0, data['SaturationPressure_MPa']+10.0, 10) P_array = -np.sort(-P_array) output = melts.equilibrate_tp(temp, P_array) pressure = [] H2Oliq = [] CO2liq = [] H2Ofl = [] CO2fl = [] fluid_wtper = [] for i in range(len(output)): (status, temp, p, xmlout) = output[i] liq_comp = melts.get_composition_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass+liq_mass) pressure.append(p) try: H2Oliq.append(liq_comp["H2O"]) except: H2Oliq.append(0) try: CO2liq.append(liq_comp["CO2"]) except: CO2liq.append(0) try: H2Ofl.append(fl_comp["H2O"]) except: H2Ofl.append(0) try: CO2fl.append(fl_comp["CO2"]) except: CO2fl.append(0) fluid_wtper.append(fl_wtper) try: sample["H2O"] = liq_comp["H2O"] except: sample["H2O"] = 0 try: sample["CO2"] = liq_comp["CO2"] except: sample["CO2"] = 0 fluid_wtper.append(fl_wtper) sample = bulk_comp_orig feasible = melts.set_bulk_composition(sample) closed_degassing_df = pd.DataFrame(list(zip(pressure, H2Oliq, CO2liq, H2Ofl, CO2fl, fluid_wtper)), columns =['pressure', 'H2Oliq', 'CO2liq', 'H2Ofl', 'CO2fl', 'fluid_wtper']) return closed_degassing_df else: P_array = np.arange(1.0, data['SaturationPressure_MPa'], 10) P_array = -np.sort(-P_array) fl_wtper = data["FluidSystem_wtper"] while fl_wtper <= init_vapor: output = melts.equilibrate_tp(temp, data["SaturationPressure_MPa"]) (status, temp, p, xmlout) = output[0] fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass+liq_mass) sample["H2O"] += fl_comp["H2O"]*0.0005 sample["CO2"] += fl_comp["CO2"]*0.0005 sample = normalize(sample) feasible = melts.set_bulk_composition(sample) output = melts.equilibrate_tp(temp, P_array) pressure = [] H2Oliq = [] CO2liq = [] H2Ofl = [] CO2fl = [] fluid_wtper = [] for i in range(len(output)): (status, temp, p, xmlout) = output[i] liq_comp = melts.get_composition_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass+liq_mass) pressure.append(p) try: H2Oliq.append(liq_comp["H2O"]) except: H2Oliq.append(0) try: CO2liq.append(liq_comp["CO2"]) except: CO2liq.append(0) try: H2Ofl.append(fl_comp["H2O"]) except: H2Ofl.append(0) try: CO2fl.append(fl_comp["CO2"]) except: CO2fl.append(0) fluid_wtper.append(fl_wtper) try: sample["H2O"] = liq_comp["H2O"] except: sample["H2O"] = 0 try: sample["CO2"] = liq_comp["CO2"] except: sample["CO2"] = 0 fluid_wtper.append(fl_wtper) sample = bulk_comp_orig feasible = melts.set_bulk_composition(sample) fl_wtper = data["FluidSystem_wtper"] exsolved_degassing_df = pd.DataFrame(list(zip(pressure, H2Oliq, CO2liq, H2Ofl, CO2fl, fluid_wtper)), columns =['pressure', 'H2Oliq', 'CO2liq', 'H2Ofl', 'CO2fl', 'fluid_wtper']) return exsolved_degassing_df elif system == 'open': P_array = np.arange(1.0, data['SaturationPressure_MPa']+10.0, 10) P_array = -np.sort(-P_array) pressure = [] H2Oliq = [] CO2liq = [] H2Ofl = [] CO2fl = [] fluid_wtper = [] for i in P_array: fl_mass = 0.0 output = melts.equilibrate_tp(temp, i) (status, temp, p, xmlout) = output[0] liq_comp = melts.get_composition_of_phase(xmlout, phase_name='Liquid') fl_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') liq_mass = melts.get_mass_of_phase(xmlout, phase_name='Liquid') fl_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') fl_wtper = 100 * fl_mass / (fl_mass+liq_mass) if fl_mass > 0: pressure.append(p) try: H2Oliq.append(liq_comp["H2O"]) except: H2Oliq.append(0) try: CO2liq.append(liq_comp["CO2"]) except: CO2liq.append(0) try: H2Ofl.append(fl_comp["H2O"]) except: H2Ofl.append(0) try: CO2fl.append(fl_comp["CO2"]) except: CO2fl.append(0) fluid_wtper.append(fl_wtper) try: sample["H2O"] = liq_comp["H2O"] except: sample["H2O"] = 0 try: sample["CO2"] = liq_comp["CO2"] except: sample["CO2"] = 0 sample = normalize(sample) feasible = melts.set_bulk_composition(sample) sample = bulk_comp_orig feasible = melts.set_bulk_composition(sample) #this needs to be reset always! open_degassing_df = pd.DataFrame(list(zip(pressure, H2Oliq, CO2liq, H2Ofl, CO2fl, fluid_wtper)), columns =['pressure', 'H2Oliq', 'CO2liq', 'H2Ofl', 'CO2fl', 'fluid_wtper']) return open_degassing_df
def calculate_saturation_pressure(self, sample, temp, print_status=False): """ Calculates the saturation pressure of one or more sample compositions, depending on what variable is passed to 'sample'. Parameters ---------- sample: dict or ExcelFile object Compositional information on one or more samples. A single sample can be passed as a dict or ExcelFile object. Multiple samples must be passed as an ExcelFile object. temp: float or str Temperature at which to calculate saturation pressures, 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 passed ExcelFile object. If so, pass the str value corresponding to the column title in the passed ExcelFile object. print_status: bool OPTIONAL: Default is False. If set to True, progress of the calculations will be printed to the terminal. Returns ------- pandas DataFrame object or dict If sample is passes as dict, dict is returned. If sample is passed as ExcelFile object, pandas DataFrame is returned. Values returned are saturation pressure in MPa, the mass of fluid present, and the composition of the fluid present. """ #--------------Preamble required for every MagmaSat method within Modeller---------------# # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel(self.model_version) # Suppress phases not required in the melts simulation self.oxides = melts.get_oxide_names() self.phases = melts.get_phase_names() for phase in self.phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) #---------------------------------------------------------------------------------------# oxides = self.oxides if isinstance(sample, dict): data = pd.DataFrame([v for v in sample.values()], index=[k for k in sample.keys()]) data = data.transpose() elif isinstance(sample, ExcelFile): data = sample.data else: raise InputError("sample must be type ExcelFile object or dict") if isinstance(temp, str): file_has_temp = True elif isinstance(temp, float): file_has_temp = False else: raise InputError("temp must be type str or float") # Do the melts equilibrations bulk_comp = {} startingP = [] startingP_ref = [] satP = [] flmass = [] flH2O = [] flCO2 = [] flsystem_wtper = [] iterno = 0 for index, row in data.iterrows(): if iterno == 0: bulk_comp_orig = {oxide: row[oxide] for oxide in oxides} bulk_comp = {oxide: row[oxide] for oxide in oxides} feasible = melts.set_bulk_composition(bulk_comp) if file_has_temp == True: temp = row[temp] fluid_mass = 0.0 press = 2000.0 while fluid_mass <= 0.0: press -= 100.0 output = melts.equilibrate_tp(temp, press, initialize=True) (status, temp, i, xmlout) = output[0] fluid_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') if press <= 0: break startingP.append(press+100.0) iterno += 1 data["StartingP"] = startingP for index, row in data.iterrows(): bulk_comp = {oxide: row[oxide] for oxide in oxides} feasible = melts.set_bulk_composition(bulk_comp) if file_has_temp == True: temp = row[temp] fluid_mass = 0.0 press = row["StartingP"] while fluid_mass <= 0.0: press -= 10.0 output = melts.equilibrate_tp(temp, press, initialize=True) (status, temp, i, xmlout) = output[0] fluid_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') if press <= 0: break startingP_ref.append(press+10.0) data["StartingP_ref"] = startingP_ref for index, row in data.iterrows(): bulk_comp = {oxide: row[oxide] for oxide in oxides} feasible = melts.set_bulk_composition(bulk_comp) if file_has_temp == True: temp = row[temp] fluid_mass = 0.0 press = row["StartingP_ref"] while fluid_mass <= 0.0: press -= 1.0 output = melts.equilibrate_tp(temp, press, initialize=True) (status, temp, i, xmlout) = output[0] fluid_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') if press <= 0: break satP.append(press) flmass.append(fluid_mass) flsystem_wtper.append(100 * fluid_mass / (fluid_mass + melts.get_mass_of_phase(xmlout, phase_name='Liquid'))) flcomp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') flH2O.append(flcomp["H2O"]) flCO2.append(flcomp["CO2"]) if print_status == True: print(index) print("Pressure = " + str(press)) print("Fluid mass = " + str(fluid_mass)) print("\n") data["SaturationPressure_MPa"] = satP data["FluidMassAtSaturation_grams"] = flmass data["H2Ofluid_wtper"] = flH2O data["CO2fluid_wtper"] = flCO2 data["FluidSystem_wtper"] = flsystem_wtper del data["StartingP"] del data["StartingP_ref"] feasible = melts.set_bulk_composition(bulk_comp_orig) #this needs to be reset always! if isinstance(sample, dict): data = data.transpose() data = data.to_dict() return data[0] elif isinstance(sample, ExcelFile): return data
def plot_isobars_and_isopleths(self, isobars_df): """ Takes in a dataframe with calculated isobar and isopleth information (e.g., output from calculate_isobars_and_isopleths) and plots data as isobars (lines of constant pressure) and isopleths (lines of constant fluid composition). These lines represent the saturation pressures of the melt composition used to calculate the isobar and isopleth information. Parameters ---------- isobars_df: pandas DataFrame DataFrame object containing isobar and isopleth information as calculated by calculate_isobars_and_isopleths. Returns ------- matplotlib object Plot with x-axis as H2O wt% in the melt and y-axis as CO2 wt% in the melt. Isobars, or lines of constant pressure at which the sample magma composition is saturated, and isopleths, or lines of constant fluid composition at which the sample magma composition is saturated, are plotted. """ #--------------Preamble required for every MagmaSat method within Modeller---------------# # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel(self.model_version) # Suppress phases not required in the melts simulation self.oxides = melts.get_oxide_names() self.phases = melts.get_phase_names() for phase in self.phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) #---------------------------------------------------------------------------------------# P_vals = isobars_df.Pressure.unique() isobars_lists = isobars_df.values.tolist() # make a list of isopleth values to plot iso_step = 20.0 isopleth_vals = np.arange(0+iso_step, 100.0, iso_step) # add zero values to volatiles list isobars_lists.append([0.0, 0.0, 0.0, 0.0]) # draw the figure fig, ax1 = plt.subplots() # turn on interactive plotting plt.ion() plt.xlabel('H2O wt%') plt.ylabel('CO2 wt%') # Plot some stuff for pressure in P_vals: ax1.plot([item[1] for item in isobars_lists if item[0] == pressure], [item[2] for item in isobars_lists if item[0] == pressure]) for val in isopleth_vals: val_min = val-1.0 val_max = val+1.0 x_vals_iso = [item[1] for item in isobars_lists if val_min <= item[3] <= val_max] x_vals_iso.append(0) x_vals_iso = sorted(x_vals_iso) x_vals_iso = np.array(x_vals_iso) y_vals_iso = [item[2] for item in isobars_lists if val_min <= item[3] <= val_max] y_vals_iso.append(0) y_vals_iso = sorted(y_vals_iso) y_vals_iso = np.array(y_vals_iso) ax1.plot(x_vals_iso, y_vals_iso, ls='dashed', color='k') labels = P_vals ax1.legend(labels) return ax1
def calculate_isobars_and_isopleths(self, sample, temp, print_status=False, pressure_min='', pressure_max='', pressure_int='', pressure_list=''): """ Calculates isobars and isopleths at a constant temperature for a given sample. Isobars can be calculated for any number of pressures. Pressures can be passed as min, max, interval (100.0, 500.0, 100.0 would result in pressures of 100.0, 200.0, 300.0, 400.0, and 500.0 MPa). Alternatively pressures can be passed as a list of all desired pressures ([100.0, 200.0, 250.0, 300.0] would calculate isobars for each of those pressures in MPa). Parameters ---------- sample: dict Dictionary with values for sample composition as oxides in wt%. temp: float Temperature in degrees C. pressure_min: float OPTIONAL. If passed, also requires pressure_max and pressure_int be passed. If passed, do not pass pressure_list. Minimum pressure value in MPa. pressure_max: float OPTIONAL. If passed, also requires pressure_min and pressure_int be passed. If passed, do not pass pressure_list. Maximum pressure value in MPa. pressure_int: float OPTIONAL: If passed, also requires pressure_min and pressure_max be passed. If passed, do not pass pressure_list. Interval between pressure values in MPa. pressure_list: list OPTIONAL: If passed, do not pass pressure_min, pressure_max, or pressure_int. List of all pressure values in MPa. print_status: bool OPTIONAL: Default is False. If set to True, progress of the calculations will be printed to the terminal. Returns ------- pandas DataFrame object DataFrame containing calcualted isobar and isopleth information for the passed melt composition. Column titles are 'Pressure', 'H2Omelt', 'CO2melt', 'H2Ofl', and 'CO2fl'. """ #--------------Preamble required for every MagmaSat method within Modeller---------------# # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel(self.model_version) bulk_comp_orig = sample #for reset # Suppress phases not required in the melts simulation self.oxides = melts.get_oxide_names() self.phases = melts.get_phase_names() for phase in self.phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) #---------------------------------------------------------------------------------------# if isinstance(pressure_min, float) and isinstance(pressure_list, list): raise InputError( "Enter pressure either as min, max, int OR as list. Not both.") if isinstance(pressure_max, float) and isinstance(pressure_list, list): raise InputError( "Enter pressure either as min, max, int OR as list. Not both.") if isinstance(pressure_int, float) and isinstance(pressure_list, list): raise InputError( "Enter pressure either as min, max, int OR as list. Not both.") if isinstance(pressure_min, float): P_vals = np.arange(pressure_min, pressure_max+pressure_int, pressure_int) if isinstance(pressure_list, list): P_vals = pressure_list bulk_comp = sample phases = self.phases oxides = self.oxides phases = melts.get_phase_names() volatiles_at_saturation = [] H2O_val = 0 CO2_val = 0 fluid_mass = 0.0 # Calculate equilibrium phase assemblage for all P/T conditions, check if saturated in fluid... for i in P_vals: if print_status == True: print("Calculating isobars at " + str(i) + " MPa") for j in np.arange(0, 15.5, 0.5): bulk_comp["H2O"] = j while fluid_mass <= 0.0: bulk_comp["CO2"] = CO2_val melts.set_bulk_composition(bulk_comp) output = melts.equilibrate_tp(temp, i, initialize=True) (status, temp, i, xmlout) = output[0] fluid_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') CO2_val = CO2_val + 0.1 if fluid_mass > 0.0: liquid_comp = melts.get_composition_of_phase( xmlout, phase_name='Liquid', mode='oxide_wt') fluid_comp = melts.get_composition_of_phase( xmlout, phase_name='Fluid') if "H2O" in liquid_comp: H2O_liq = liquid_comp["H2O"] else: H2O_liq = 0 if "CO2" in liquid_comp: CO2_liq = liquid_comp["CO2"] else: CO2_liq = 0 if "H2O" in fluid_comp: H2O_fl = fluid_comp["H2O"] else: H2O_fl = 0.0 if "CO2" in fluid_comp: CO2_fl = fluid_comp["CO2"] else: CO2_fl = 0.0 volatiles_at_saturation.append( [i, H2O_liq, CO2_liq, H2O_fl, CO2_fl]) CO2_val = 0.0 fluid_mass = 0.0 if print_status == True: print("Done!") isobars_df = pd.DataFrame(volatiles_at_saturation, columns=[ 'Pressure', 'H2Omelt', 'CO2melt', 'H2Ofl', 'CO2fl']) feasible = melts.set_bulk_composition(bulk_comp_orig) #reset return isobars_df
def calculate_equilibrium_fluid_comp(self, sample, temp, press): """ Returns H2O and CO2 concentrations in wt% in a fluid in equilibrium with the given sample(s) at the given P/T condition. Parameters ---------- sample: dict or ExcelFile object Compositional information on one or more samples. A single sample can be passed as a dict or ExcelFile object. Multiple samples must be passed as an ExcelFile object. temp: float 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 passed ExcelFile object. If so, pass the str value corresponding to the column title in the passed ExcelFile object. press: float or str Pressure, in MPa. Can be passed as float, 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 passed ExcelFile object. If so, pass the str value corresponding to the column title in the passed ExcelFile object. Returns ------- dict If dict is passed to sample, a dictionary of fluid composition in wt% with keys 'H2O' and 'CO2' is returned. If ExcelFile is passed to sample, a pandas DataFrame object is returned. """ #--------------Preamble required for every MagmaSat method within Modeller---------------# # instantiate thermoengine equilibrate MELTS instance melts = equilibrate.MELTSmodel(self.model_version) # Suppress phases not required in the melts simulation self.oxides = melts.get_oxide_names() self.phases = melts.get_phase_names() for phase in self.phases: melts.set_phase_inclusion_status({phase: False}) melts.set_phase_inclusion_status({'Fluid': True, 'Liquid': True}) #---------------------------------------------------------------------------------------# if isinstance(sample, dict): bulk_comp_orig = sample #for reset data = pd.DataFrame([v for v in sample.values()], index=[k for k in sample.keys()]) data = data.transpose() elif isinstance(sample, ExcelFile): data = sample.data else: raise InputError("sample must be type ExcelFile object or dict") if isinstance(temp, str): file_has_temp = True elif isinstance(temp, float): file_has_temp = False else: raise InputError("temp must be type str or float") if isinstance(press, str): file_has_press = True elif isinstance(temp, float): file_has_press = False else: raise InputError("press must be type str or float") fluid_comp_H2O = [] fluid_comp_CO2 = [] for index, row in data.iterrows(): bulk_comp = {oxide: row[oxide] for oxide in oxides} feasible = melts.set_bulk_composition(bulk_comp) if file_has_temp == True: temp = row[temp] if file_has_press == True: press = row[press] output = melts.equilibrate_tp(temp, press, initialize=True) (status, temp, i, xmlout) = output[0] fluid_mass = melts.get_mass_of_phase(xmlout, phase_name='Fluid') if fluid_mass > 0.0: fluid_comp = melts.get_composition_of_phase(xmlout, phase_name='Fluid') fluid_comp_H2O.append(fluid_comp['H2O']) fluid_comp_CO2.append(fluid_comp['CO2']) else: fluid_comp_H2O.append(0) fluid_comp_CO2.append(0) data["H2Ofluid_wtper"] = fluid_comp_H2O data["CO2fluid_wtper"] = fluid_comp_CO2 if isinstance(sample, dict): feasible = melts.set_bulk_composition(bulk_comp_orig) #reset data = pd.DataFrame({"H2O": data["H2Ofluid_wtper"], "CO2": data["CO2fluid_wtper"]}) data = data.transpose() data = data.to_dict() return data[0] elif isinstance(sample, ExcelFile): return data