This page was generated from docs/Examples/Mantle_Melting_Lee_Wieser/Complex_melt_changing_SCSS.ipynb. Interactive online version: .
Calculating sulfur and trace element evolution during mantle melting with changing SCSS and KDs
This notebook shows how to use the mantle melting model of Lee et al. (2012) adapted by Wieser et al. (2020) to model how S, Cu and other chalcophile or lithophile elements evolve during mantle melting
For more information on how the math works, we direct you towards the supporting information of Wieser et al (2020) - https://doi.org/10.1016/j.gca.2020.05.018 - Where the equations are typed out in detail
Here, we do the more complex example where silicate modes change and SCSS and KD change
Loading libraries
[1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import PySulfSat as ss
Example 1 - Non fixed S content
The examples in the other workbook assume that S is fixed throughout the melting interval
However, we know the concentration of mantle melts changes with increasing F, so ideally, we’d calculate how much S those melts can hold
We can do this using an output from a melting model (here, Thermocalc).
[2]:
# Load a generic dataframe
Thermocalc_df=pd.read_excel('Thermocalc_Melting_Path.xlsx')
[3]:
# Load a dataframe for calculating SCSS for these melt comps
Thermo_df_ss=ss.import_data('Thermocalc_Melting_Path.xlsx',
suffix='_Liq')
We have replaced all missing liquid oxides and strings with zeros.
Calculate instanteous melts
This dataframe contains aggregated melt compositions, we need instantenous melts for calculating the SCSS
[4]:
Inst_Liq=ss.calculate_inst_melts_Thermocalc(Thermocalc_df=Thermocalc_df)
Inst_Liq.head()
[4]:
SiO2_Liq | Al2O3_Liq | CaO_Liq | MgO_Liq | FeO_Liq | Na2O_Liq | Fe2O3_Liq | FeOt_Liq | |
---|---|---|---|---|---|---|---|---|
0 | 48.30 | 15.09 | 10.22 | 12.50 | 9.40 | 3.88 | 0.54 | 9.885892 |
1 | 48.20 | 15.07 | 10.35 | 12.57 | 9.41 | 3.80 | 0.52 | 9.877896 |
2 | 48.02 | 15.01 | 10.59 | 12.71 | 9.43 | 3.62 | 0.50 | 9.879900 |
3 | 47.84 | 14.98 | 10.86 | 12.88 | 9.45 | 3.47 | 0.48 | 9.881904 |
4 | 47.66 | 14.90 | 11.08 | 13.00 | 9.47 | 3.31 | 0.46 | 9.883908 |
TiO\(_2\) is very bad from Thermocalc, lets calculate it using our melting functions here
[5]:
KDs_TiO2=pd.DataFrame(data={'element': 'TiO2',
'ol': 0.07, 'opx': 0.07,
'cpx': 0.07, 'sp': 0.07,
'gt': 0.07, 'sulf': 0.07}, index=[0])
Extract the modes from Thermocalc
[6]:
Modes3=pd.DataFrame(data={'ol': Thermocalc_df['ol'],
'cpx': Thermocalc_df['cpx'],
'opx': Thermocalc_df['opx'],
'sp': Thermocalc_df['sp'],
'gt': Thermocalc_df['g']*0})
[7]:
df_TiO2_Thermocalc=ss.Lee_Wieser_sulfide_melting(F=Thermocalc_df['liq'],
Modes=Modes3,
KDs=KDs_TiO2,
S_Sulf=330000, elem_Per=0.13,
S_Mantle=[200],
S_Melt_SCSS_2_ppm=1000,
Prop_S6=0)
Inst_Liq['TiO2_Liq']=df_TiO2_Thermocalc['TiO2_Melt_Inst']
Lets calculate the SCSS using ONeill (2021)
Wieser et al. (2020) show that the calculated sulfide composition isn’t very reliable at mantle PT, so we use a fixed mantle S composition of Fe/(Fe+Ni+Cu)=0.634
[8]:
SCSS_fixedSulf=ss.calculate_O2021_SCSS(df=Inst_Liq,
T_K=Thermocalc_df['T']+273.15, P_kbar=Thermocalc_df['P'],
Fe_FeNiCu_Sulf=0.634)
SCSS_fixedSulf.head()
Using inputted Fe_FeNiCu_Sulf ratio for calculations.
[8]:
SCSS2_ppm | LnS | Ln_a_FeO | Ln_a_FeS | DeltaG | LnCS2_calc | SiO2_Liq | Al2O3_Liq | CaO_Liq | MgO_Liq | FeO_Liq | Na2O_Liq | Fe2O3_Liq | FeOt_Liq | TiO2_Liq | P2O5_Liq | Fe_FeNiCu_Sulf_calc | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1044.741097 | 6.951524 | -2.187206 | -0.532776 | 6.105676 | -0.808582 | 48.30 | 15.09 | 10.22 | 12.50 | 9.40 | 3.88 | 0.54 | 9.885892 | 0.000000 | 0 | 0.634 |
1 | 1103.032862 | 7.005819 | -2.246978 | -0.531748 | 6.098787 | -0.808198 | 48.20 | 15.07 | 10.35 | 12.57 | 9.41 | 3.80 | 0.52 | 9.877896 | 1.860432 | 0 | 0.634 |
2 | 1116.546495 | 7.017996 | -2.245749 | -0.531987 | 6.091909 | -0.787675 | 48.02 | 15.01 | 10.59 | 12.71 | 9.43 | 3.62 | 0.50 | 9.879900 | 1.613651 | 0 | 0.634 |
3 | 1131.497103 | 7.031297 | -2.244104 | -0.532091 | 6.085093 | -0.765808 | 47.84 | 14.98 | 10.86 | 12.88 | 9.45 | 3.47 | 0.48 | 9.881904 | 1.396916 | 0 | 0.634 |
4 | 1146.297359 | 7.044292 | -2.243501 | -0.532328 | 6.078288 | -0.745169 | 47.66 | 14.90 | 11.08 | 13.00 | 9.47 | 3.31 | 0.46 | 9.883908 | 1.206812 | 0 | 0.634 |
Now we are ready to model S-Cu
instead of inputting a single value for S_melt_SCSS_2_ppm, we input the pandas dataframe.
[9]:
KDs_Cu=pd.DataFrame(data={'element': 'Cu',
'ol': 0.048, 'opx': 0.034,
'cpx': 0.043, 'sp': 0.223,
'gt': 0, 'sulf': 800}, index=[0])
Modes=pd.DataFrame(data={'ol': 0.6, 'opx': 0.2,
'cpx': 0.18, 'sp': 0.02, 'gt': 0}, index=[0])
# Lets run the simple model for comparison
S_Sulf = 38*(10**4)
df_Cu_200S=ss.Lee_Wieser_sulfide_melting(F=Thermocalc_df['liq'],
Modes=Modes,
KDs=KDs_Cu,
S_Sulf=S_Sulf, elem_Per=30,
S_Mantle=[200],
S_Melt_SCSS_2_ppm=1000,
Prop_S6=0)
# Now lets change S
df_Cu_200S_Thermocalc=ss.Lee_Wieser_sulfide_melting(F=Thermocalc_df['liq'],
Modes=Modes3,
KDs=KDs_Cu,
S_Sulf=S_Sulf, elem_Per=30,
S_Mantle=[200],
S_Melt_SCSS_2_ppm=SCSS_fixedSulf['SCSS2_ppm'],
Prop_S6=0)
[10]:
fig, ((ax1, ax2, ax3)) = plt.subplots(1, 3, figsize=(12,4), sharex=True)
# 100 ppm
ax1.plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['Cu_Melt_Agg'].iloc[1:],
'-',color='m', ms=10, label='Cu, S=200, fixed SCSS')
# Lets add a cross to show the point at which sulfide is exhausted
sulf_out_200=np.take(np.where(df_Cu_200S['S_Residue']==0), 0)
ax1.plot(df_Cu_200S['F'].loc[sulf_out_200],
df_Cu_200S['Cu_Melt_Agg'].loc[sulf_out_200],
'*k', ms=10, label='Sulf out')
ax1.plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['Cu_Melt_Agg'].iloc[1:],
'-',color='c', ms=10, label='Cu, S=200, O2021 SCSS')
# Lets add a cross to show the point at which sulfide is exhausted
sulf_out_200=np.take(np.where(df_Cu_200S_Thermocalc['S_Residue']==0), 0)
ax1.plot(df_Cu_200S_Thermocalc['F'].loc[sulf_out_200],
df_Cu_200S_Thermocalc['Cu_Melt_Agg'].loc[sulf_out_200],
'*k', ms=10, label='Sulf out')
ax1.set_xlim([0, 0.5])
ax1.set_xlabel('F')
ax1.set_ylabel('Cu (ppm')
# Plot S in melt
ax2.plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['S_Melt_Agg'].iloc[1:],
'-',color='m', ms=10, label='Cu, S=200, fixed SCSS')
ax2.plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['S_Melt_Agg'].iloc[1:],
'-',color='c', ms=10, label='Cu, S=200, O2021 SCSS')
ax2.set_xlabel('F')
ax2.set_ylabel('input S in melt (ppm)')
# S in source
ax3.plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['S_Residue'].iloc[1:],
'-',color='m', ms=10, label='Cu, S=200, fixed SCSS')
ax3.plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['S_Residue'].iloc[1:],
'-',color='c', ms=10, label='Cu, S=200, O2021 SCSS')
ax3.set_xlabel('F')
ax3.set_ylabel('S in residue (ppm)')
fig.tight_layout()
ax1.legend()
ax2.set_ylim([0, 1500])
[10]:
(0.0, 1500.0)
Example 2 - Variable KD
We can be even ‘cleverer’ than this. So far, we have assumed the KDs stay constant, but that isn’t the case. We know from Kiseeva et al. (2015) that the KD of Cu in the sulfide depends on the FeOt content of the melt, the sulfide composition and the temperature.
Following Ding and Dasgupta, lets calculate KD using 5 wt% Cu and 20 wt% Ni in the mantle sulfide
Calculate KD using Kiseeva, using a fixed sulfide composition.
[11]:
Sulf_KDs_Kis=ss.calculate_sulf_kds(Ni_Sulf=5, Cu_Sulf=20,
FeOt_Liq=Thermocalc_df['FeOt'],
T_K=Thermocalc_df['T']+273.15, Fe3Fet_Liq=0)
Sulf_KDs_Kis.head()
[11]:
S_Sulf | O_Sulf | Fe_Sulf | Ni_Sulf | Cu_Sulf | DNi | DCu | DAg | DPb | DZn | ... | DIn | DTi | DGa | DSb | DCo | DV | DGe | DCr | DSe_B2015 | DTe_B2015 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 28.951975 | 2.040467 | 44.007558 | 5 | 20 | 468.888700 | 423.437545 | 387.173238 | 24.179410 | 2.000184 | ... | 13.909661 | 0.009705 | 0.069138 | 31.618608 | 33.696187 | 0.213793 | 1.418172 | 1.365763 | 1194.743950 | 11164.888225 |
1 | 28.954668 | 2.038823 | 44.006509 | 5 | 20 | 467.544755 | 421.716344 | 385.632376 | 24.167264 | 2.003319 | ... | 13.914218 | 0.009722 | 0.069545 | 31.714442 | 33.678820 | 0.214521 | 1.425514 | 1.369429 | 1195.816660 | 11175.374871 |
2 | 28.954331 | 2.039029 | 44.006641 | 5 | 20 | 465.786726 | 419.721374 | 383.854833 | 24.132319 | 2.004770 | ... | 13.901989 | 0.009734 | 0.069894 | 31.771584 | 33.629184 | 0.215073 | 1.430966 | 1.371968 | 1195.682200 | 11174.060687 |
3 | 28.953993 | 2.039235 | 44.006772 | 5 | 20 | 464.050446 | 417.753198 | 382.100957 | 24.097713 | 2.006208 | ... | 13.889863 | 0.009746 | 0.070241 | 31.828280 | 33.580030 | 0.215621 | 1.436388 | 1.374488 | 1195.547751 | 11172.746524 |
4 | 28.953656 | 2.039441 | 44.006904 | 5 | 20 | 462.323330 | 415.797345 | 380.357852 | 24.063208 | 2.007645 | ... | 13.877764 | 0.009758 | 0.070590 | 31.884979 | 33.531021 | 0.216170 | 1.441821 | 1.377008 | 1195.413312 | 11171.432383 |
5 rows × 23 columns
Now lets make a dataframe of KDs
You could also set the silicate KDs to vary based on any other Kd models you have for them in the same way as above/
[12]:
KDs_Cu_Kis=pd.DataFrame(data={'element': 'Cu',
'ol': 0.048, 'opx': 0.034,
'cpx': 0.043, 'sp': 0.223,
'gt': 0, 'sulf': Sulf_KDs_Kis['DCu']})
[13]:
fig, ((ax1, ax2, ax3)) = plt.subplots(1, 3, figsize=(10,4))
ax1.plot(Thermocalc_df['liq'],
Sulf_KDs_Kis['DCu'], '-k')
ax1.set_xlabel('F')
ax1.set_ylabel('D$_{Cu}$')
ax2.plot(Thermocalc_df['FeOt'],
Sulf_KDs_Kis['DCu'], '-k')
ax2.set_xlabel('FeOt')
ax2.set_ylabel('D$_{Cu}$')
ax3.plot(Thermocalc_df['T'],
Sulf_KDs_Kis['DCu'], '-k')
ax3.set_xlabel('T')
ax3.set_ylabel('D$_{Cu}$')
fig.tight_layout()
[14]:
df_Cu_200S_Thermocalc_Kis=ss.Lee_Wieser_sulfide_melting(F=Thermocalc_df['liq'],
Modes=Modes3,
KDs=KDs_Cu_Kis,
S_Sulf=S_Sulf, elem_Per=30,
S_Mantle=[200],
S_Melt_SCSS_2_ppm=SCSS_fixedSulf['SCSS2_ppm'],
Prop_S6=0)
# Lets also model Selenium
df_Cu_200S_Thermocalc_Kis=ss.Lee_Wieser_sulfide_melting(F=Thermocalc_df['liq'],
Modes=Modes3,
KDs=KDs_Cu_Kis,
S_Sulf=S_Sulf, elem_Per=30,
S_Mantle=[200],
S_Melt_SCSS_2_ppm=SCSS_fixedSulf['SCSS2_ppm'],
Prop_S6=0)
[15]:
#fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(10,8))
figure_mosaic="""
AB
AC
"""
fig,axes=plt.subplot_mosaic(mosaic=figure_mosaic, figsize=(9, 3.5), sharex=True)
axes['A'].plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['Cu_Melt_Agg'].iloc[1:],
'--',color='m', ms=10, label='Cu, S=200 ppm, simple')
# Lets add a cross to show the point at which sulfide is exhausted
sulf_out_200=np.take(np.where(df_Cu_200S['S_Residue']==0), 0)
axes['A'].plot(df_Cu_200S['F'].loc[sulf_out_200],
df_Cu_200S['Cu_Melt_Agg'].loc[sulf_out_200],
'*k', ms=10, label='Sulf out')
# Kiseeva KDs, O2021 SCSS
axes['A'].plot(df_Cu_200S_Thermocalc_Kis['F'].iloc[1:],
df_Cu_200S_Thermocalc_Kis['Cu_Melt_Agg'].iloc[1:],
'-',color='b', ms=10, label='Cu, S=200 ppm, Kiseeva KDs, O2021 SCSS')
# Lets add a cross to show the point at which sulfide is exhausted
sulf_out_200=np.take(np.where(df_Cu_200S_Thermocalc_Kis['S_Residue']==0), 0)
axes['A'].plot(df_Cu_200S_Thermocalc_Kis['F'].loc[sulf_out_200],
df_Cu_200S_Thermocalc_Kis['Cu_Melt_Agg'].loc[sulf_out_200],
'*k', ms=10, label='Sulf out')
# FixedKD, O2021 SCSS
axes['A'].plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['Cu_Melt_Agg'].iloc[1:],
'-',color='c', ms=10, label='Cu, S=200, KD=800, O2021 SCSS')
# Lets add a cross to show the point at which sulfide is exhausted
sulf_out_200=np.take(np.where(df_Cu_200S_Thermocalc['S_Residue']==0), 0)
axes['A'].plot(df_Cu_200S_Thermocalc['F'].loc[sulf_out_200],
df_Cu_200S_Thermocalc['Cu_Melt_Agg'].loc[sulf_out_200],
'*k', ms=10, label='Sulf out')
axes['A'].set_xlim([0, 0.5])
axes['A'].set_xlabel('F (degree of melting)')
axes['A'].set_ylabel('Melt Cu$_{Aggregated}$ (ppm)')
axes['A'].set_ylim([0, 170])
axes['B'].plot(df_Cu_200S_Thermocalc_Kis['F'].iloc[1:],
KDs_Cu_Kis['sulf'].iloc[1:], '-b')
axes['B'].plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['F'].iloc[1:]*0+800, '-c')
axes['B'].plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['F'].iloc[1:]*0+800, '--m')
axes['B'].set_ylabel('K$_D$ Cu')
axes['C'].plot(df_Cu_200S_Thermocalc_Kis['F'].iloc[1:],
df_Cu_200S_Thermocalc_Kis['S_Melt_Agg'].iloc[1:], '-b')
axes['C'].plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['S_Melt_Agg'].iloc[1:], '-c')
axes['C'].plot(df_Cu_200S['F'].iloc[1:],
df_Cu_200S['S_Melt_Agg'].iloc[1:], '--m')
axes['C'].set_xlabel('F (degree of melting)')
axes['C'].set_ylabel('Melt S$_{Aggregated}$ (ppm)')
fig.tight_layout()
fig.savefig('Complex_Models.png', dpi=300)
[16]:
plt.plot(df_Cu_200S_Thermocalc['F'].iloc[1:],
df_Cu_200S_Thermocalc['S_Melt_Agg'].iloc[1:], '-c')
[16]:
[<matplotlib.lines.Line2D at 0x17dd803baf0>]
[ ]:
[ ]: