# Xtools

### Written by Oliver T Lord

#### School of Earth Sciences, University of Bristol

Copyright 2018 Oliver Lord

This file is part of Xtools.

Xtools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Xtools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Xtools. If not, see http://www.gnu.org/licenses/.

# PVT calculator

Determine the unit cell volume for a range of important deep Earth phases and XRD standards at a given P & T using equations of state from the literature

``````

In [8]:

%%capture
!jupyter nbextension enable --py --sys-prefix widgetsnbextension

``````
``````

In [9]:

import ipywidgets as widgets
import numpy as np
import sys
import array
import matplotlib.pyplot as plt

from ipywidgets import Layout, HBox, VBox, Dropdown, interactive, interact, Label
from IPython.core.display import display
from scipy.optimize import fsolve
from scipy.integrate import quad

``````
``````

In [10]:

global P_max, phase, EoS
P, P_max, V0, EoS, phase, ref, K, Kp, a0, b0, c0 = 0, 200, 162.373, 1, 1, 1, 256.7, 4.09, 4.7769, 4.9284, 6.8972
D0, g0, g_inf, q, apfu, apuc = 950, 1.54, 1, 1.5, 5, 4
VT = V0

def phases(phase,EoS,ref):
global V0, K, Kp, a0, b0, c0, D0, g0, g_inf, q, apfu, apuc
if phase == 'MgSiO3 perovskite':
#Data from: Tange et al. (2012) 10.1029/2011JB008988
dropdown3.options, dropdown3.disabled = ['Tange et al. (2012)'], True
dropdown2.options, dropdown2.disabled = ['3rd Order Birch-Murnaghan','Vinet'], False
if EoS == '3rd Order Birch-Murnaghan':
V0, K, Kp, a0, b0, c0 = 162.373, 256.7, 4.09, 4.7769, 4.9284, 6.8972
D0, g0, g_inf, q, apfu, apuc = 950, 1.54, 1, 1.5, 5, 4
if EoS =='Vinet':
V0, K, Kp, a0, b0, c0 = 162.373, 258.4, 4.1, 4.7769, 4.9284, 6.8972
D0, g0, g_inf, q, apfu, apuc = 940, 1.55, 1, 1.1, 5, 4
if phase == 'MgCO3 magnesite':
#Data from: Fiquet et al. (2002) American Mineralogist 87:1261-1265
dropdown2.value, dropdown2.disabled = '3rd Order Birch-Murnaghan', True
dropdown3.options, dropdown3.disabled = ['Fiquet et al. (2002)'], True
V0, K, Kp, a0, b0, c0 = 279.2, 108, 5, 4.6377, 4.6377, 15.007
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'SiO2 stishovite':
#Data from: Wang et al. (2012) 10.1029/2011JB009100
dropdown3.options, dropdown3.disabled = ['Wang et al. (2012)'], True
dropdown2.options, dropdown2.disabled = ['3rd Order Birch-Murnaghan','Vinet'], False
if EoS == '3rd Order Birch-Murnaghan':
V0, K, Kp, a0, b0, c0 = 46.55, 294, 4.85, 4.66, 4.66, 2.8403
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if EoS == 'Vinet':
V0, K, Kp, a0, b0, c0 = 46.55, 292, 5.01, 4.66, 4.66, 2.8403
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'Pt':
#Data from: Dorogokupets & Dewaele (2007) 10.1080/08957950701659700
dropdown2.value, dropdown2.disabled = '3rd Order Birch-Murnaghan', True
dropdown3.options, dropdown3.disabled = ['Dorogokupets & Dewaele (2007)'], True
V0, K, Kp, a0, b0, c0 = 60.38, 277.3, 5.12, 3.9231, 3.9231, 3.9231
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'Au':
#Data from: Fei et al. (2012) 10.1073/pnas.0609013104
dropdown3.options, dropdown3.disabled = ['Fei et al. (2012)'], True
dropdown2.options, dropdown2.disabled = ['3rd Order Birch-Murnaghan','Vinet'], False
if EoS == '3rd Order Birch-Murnaghan':
V0, K, Kp, a0, b0, c0 = 67.85, 167, 5.77, 4.0786, 4.0786, 4.0786
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if EoS == 'Vinet':
V0, K, Kp, a0, b0, c0 = 67.85, 167, 6.00, 4.0786, 4.0786, 4.0786
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'NaCl B1':
dropdown3.options, dropdown3.disabled = ['Dorogokupets & Dewaele (2007)', 'Decker (1971)'], False
dropdown2.options, dropdown2.disabled = ['3rd Order Birch-Murnaghan','Vinet'], True
#Data from: Dorogokupets & Dewaele (2007) 10.1080/08957950701659700
if ref == 'Dorogokupets & Dewaele (2007)':
dropdown2.value = 'Vinet'
V0, K, Kp, a0, b0, c0 = 179.44, 23.83, 5.09, 5.6404, 5.6404, 5.6404
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
#Data from: Decker (1971) 10.1080/08957950701659700
if ref == 'Decker (1971)':
dropdown2.value = '3rd Order Birch-Murnaghan'
V0, K, Kp, a0, b0, c0 = 179.43, 24.02, 4.74, 5.6402, 5.6402, 5.6402
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'NaCl B2':
#Data from: Dorogokupets & Dewaele (2007) 10.1080/08957950701659700
dropdown2.value, dropdown2.disabled = 'Vinet', True
dropdown3.options, dropdown3.disabled = ['Dorogokupets & Dewaele (2007)'], True
V0, K, Kp, a0, b0, c0 = 40.73, 29.72, 5.14, 3.4407, 3.4407, 3.4407
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
if phase == 'CO2-V':
#Data from: Datchi et al. (2012) 10.1103/PhysRevLett.108.125701
dropdown2.value, dropdown2.disabled = 'Vinet', True
dropdown3.options, dropdown3.disabled = ['Datchi et al. (2012)'], True
V0, K, Kp, a0, b0, c0 = 90.99, 136.0, 4, 3.4407, 3.4407, 3.4407
#V0, K, Kp, a0, b0, c0 = 90.99, 136.0, 3.7, 3.7939, 3.7939, 6.3221
D0, g0, g_inf, q, apfu, apuc = 1, 0, 0, 1, 1, 1
initialise(EoS)

def phase_selector(phase):
dropdown2.value, dropdown2.disabled = 'MgSiO3 perovskite', False
dropdown3.value, dropdown3.disabled = '3rd Order Birch-Murnaghan', False
phases

def EoS_selector(EoS):
phases

def ref_selector(ref):
phases

def initialise(EoS):
K_box.value = ("K = " + str(K) + " GPa")
Kp_box.value = ("K' = " + str(Kp))
V0_box.value = ("V₀ = " + str(V0) + " Å³")

def BM3(V,P):
return P-((3/2)*(K*(((V0/V)**(7/3))-((V0/V)**(5/3)))*(1-(((3/4)*(4-Kp))*(((V0/V)**(2/3))-1)))))

def Vinet(V,P):
return P-(3*K*((1-((V/V0)**(1/3)))/((V/V0)**(2/3)))*np.exp((3/2)*(Kp-1)*(1-((V/V0)**(1/3)))))

phase_items = ['MgSiO3 perovskite', 'MgCO3 magnesite', 'SiO2 stishovite', 'Pt', 'Au','NaCl B1','NaCl B2', 'CO2-V']
EoS_items = ['3rd Order Birch-Murnaghan', 'Vinet']

dropdown1 = widgets.Dropdown(options = phase_items,description='Phase:',layout=Layout(width='75.4%'))
dropdown2 = widgets.Dropdown(options = EoS_items,description='EoS:',layout=Layout(width='75.4%'),disabled=False)
dropdown3 = widgets.Dropdown(options = ['Tange et al. (2012)'],description='Ref:',layout=Layout(width='75.4%'),disabled=True)

w1=widgets.interactive(phase_selector,phase=dropdown1,EoS=dropdown2,ref=dropdown3)
w2=widgets.interactive(phases,phase=dropdown1,EoS=dropdown2,ref=dropdown3)
w3=widgets.interactive(phases,phase=dropdown1,EoS=dropdown2,ref=dropdown3)

K_box = widgets.Text(disabled=True,description='Parameters',layout=Layout(width='35%'))
Kp_box = widgets.Text(disabled=True,layout=Layout(width='19.8%'))
V0_box = widgets.Text(disabled=True,layout=Layout(width='19.8%'))

initialise('3rd Order Birch-Murnaghan')
VBox([HBox([dropdown1]), HBox([dropdown2]), HBox([dropdown3]), HBox([K_box, Kp_box, V0_box])])

``````
``````

var element = \$('#e8e3dc93-1801-4ac0-b029-3ee1c8d55083');

{"model_id": "d65a3031f5f540d2a7d30368751af8ef", "version_major": 2, "version_minor": 0}

``````
``````

In [11]:

global P_max, phase, EoS, V0, K, Kp, a0, b0, c0

def V_calc(P,T):

if g0 == 0:
T_slider.value, T_slider.disabled = 300, True
else:
T_slider.disabled = False

VVT_box.description = (str(round(T_slider.value)) + 'K:')
P_range, V_range, VT_range = list(range(0,P_max+1,4)), list(range(0,P_max+1,4)), list(range(0,P_max+1,4))

if EoS == 1:
Vp = fsolve(lambda V,P: BM3(V,P), 1, args=(P), xtol=1e-5)
VT = VT_calc(Vp,P,T)

for i, j in enumerate(P_range):

V_range[i] = fsolve(lambda V,P: BM3(V,P), 1, args=(j), xtol=1e-5)

if T != 300:
VT_range[i] = VT_calc(Vp,j,T)
else:
VT_range[i] = V_range[i]

if EoS == 2:
Vp = fsolve(lambda V,P: Vinet(V,P), 1, args=(P), xtol=1e-5)
VT = VT_calc(Vp,P,T)

for i, j in enumerate(P_range):

V_range[i] = fsolve(lambda V,P: Vinet(V,P), 1, args=(j), xtol=1e-5)

if T != 300:
VT_range[i] = VT_calc(Vp,j,T)
else:
VT_range[i] = V_range[i]

VV_box.value = ("V = " + str(np.around(Vp,3))[1:-1] + " Å³")
Va_box.value = ("a = " + str(np.around((Vp/V0)**(1/3)*a0,3))[1:-1] + " Å")
Vb_box.value = ("b = " + str(np.around((Vp/V0)**(1/3)*b0,3))[1:-1] + " Å")
Vc_box.value = ("c = " + str(np.around((Vp/V0)**(1/3)*c0,3))[1:-1] + " Å")

VVT_box.value = ("V = " + str(np.around(VT,3))[1:-1] + " Å³")
VaT_box.value = ("a = " + str(np.around((Vp/V0)**(1/3)*a0,3))[1:-1] + " Å")
VbT_box.value = ("b = " + str(np.around((Vp/V0)**(1/3)*b0,3))[1:-1] + " Å")
VcT_box.value = ("c = " + str(np.around((Vp/V0)**(1/3)*c0,3))[1:-1] + " Å")

PVT_plot(P_max,P_range,V_range,P,Vp,VT,VT_range)

def PVT_plot(P_max,P_range,V_range,P,Vp,VT,VT_range):
plt.figure(num=1, figsize=(10.72, 6), dpi=80, facecolor='w', edgecolor='k')
line1, line2, line3, line4 = plt.plot(P_range,VT_range,'r-',P_range,V_range,'b-',P,VT,'ro',P,Vp,'bo')
plt.xlim(-P_max*0.02, P_max*1.02)
plt.ylim(V_range[-1]*.98, VT_range[0]*1.02)
plt.ylabel('Unit Cell Volume (Å³)', fontsize=18)
plt.xlabel('Pressure (GPa)', fontsize=18)

def VT_calc(V,P,T):
VT = fsolve(lambda V,P,T: MGD(V,P,T), 1, args=(P,T), xtol=1e-5)
return(VT)

def MGD(Vp,P,T):
if EoS == 1:
P300 = ((3/2)*(K*(((V0/Vp)**(7/3))-((V0/Vp)**(5/3)))*(1-(((3/4)*(4-Kp))*(((V0/Vp)**(2/3))-1)))))
if EoS == 2:
P300 = (3*K*((1-((Vp/V0)**(1/3)))/((Vp/V0)**(2/3)))*np.exp((3/2)*(Kp-1)*(1-((Vp/V0)**(1/3)))))
P300=((3/2)*(K*(((V0/Vp)**(7/3))-((V0/Vp)**(5/3)))*(1-(((3/4)*(4-Kp))*(((V0/Vp)**(2/3))-1)))))
g = g_inf+(g0-g_inf)*(Vp/V0)**q
D = D0*(Vp/V0)**-g
int_T = quad(debye_integrand, 0, D/T)
int_300 = quad(debye_integrand, 0, D/300)
E_T = 9*apfu*8.314472*T*((T/D)**3)*int_T[0]
E_300 = 9*apfu*8.314472*300*((300/D)**3)*int_300[0]
PTH = (E_T-E_300)*(g/(((Vp/apuc)*6.022E+23)/1E+21))
PTOTAL = P300 + PTH
return PTOTAL-P

def debye_integrand(x):
return x**3/((np.exp(x) - 1))

P_slider = widgets.FloatSlider(min=0, max=200, step=0.1, value=0, description='P in GPa:',layout=Layout(width='76.9%'),continuous_update=False)
P_slider.style.handle_color = 'lightblue'

T_slider = widgets.FloatSlider(min=300, max=3000, step=1, value=300, description='T in K:',layout=Layout(width='76.9%'),continuous_update=False)
T_slider.style.handle_color = 'lightblue'

widgets.interactive(V_calc,P=P_slider, T=T_slider)

VV_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'),description=('300K:'))
Va_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))
Vb_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))
Vc_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))

VVT_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'),description=(str(round(T_slider.value)) + 'K:'))
VaT_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))
VbT_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))
VcT_box = widgets.Text(disabled=True,layout=Layout(width='18.55%'))

intwidget = interactive(V_calc, P=P_slider, T=T_slider)
intoutput = intwidget.children[-1]
display(VBox([HBox([P_slider]), HBox([T_slider]), HBox([VV_box, Va_box, Vb_box, Vc_box]), HBox([VVT_box, VaT_box, VbT_box, VcT_box]), HBox([intoutput])]))
intwidget.update()

``````
``````

var element = \$('#c23a2975-0029-4933-a0d2-c0cef028c0cd');

{"model_id": "160bf079c25343c984d08036576b93d5", "version_major": 2, "version_minor": 0}

``````

# Ruby Fluorescence and Raman Diamond pressure calibration

Determine pressure from the peak position of the ruby R1 fluorescence peak or the diamond 001 raman mode

``````

In [12]:

A, B = 1904, 9.500

def ruby_scale(scale1):
global A, B
if scale1 == 1:
#Data from: Dewaele et al. (2004) 10.1103/PhysRevB.70.094112
A, B = 1904, 9.500
if scale1 == 2:
#Data from: Mao et al. (1986)
A, B = 1904, 7.665
initialise2()

def raman_scale(scale2):
return scale2

def ruby(R1):
R1_0,V1_0=get_boxes()
delta=R1-R1_0
ruby_P=A/B*((1+delta/R1_0)**B-1)
P_slider2.value=ruby_P
raman_slider.value=(ruby_P*(1/0.501))+V1_0

def raman(V1):
R1_0,V1_0=get_boxes()
print(R1_0,V1_0)
raman_P=0.501*(V1-V1_0)
P_slider2.value=raman_P
ruby_slider.value=R1_0*(((B*((A/B)+raman_P))/A)**(1/B))

def cal_plot(i):
R1_0,V1_0=get_boxes()
dV = raman_slider.value-V1_0
dV_range = np.arange(0., (raman_slider.max-V1_0), 0.2)
plt.figure(num=1, figsize=(10.72, 6), dpi=80, facecolor='w', edgecolor='k')
line1, line2, = plt.plot(dV_range, dV_range*0.501, 'r-', dV, dV*0.501,  'bo')
plt.ylim(0, P_slider2.max)
plt.xlim(0, raman_slider.max-V1_0)
plt.ylabel('Ruby Pressure (GPa)', fontsize=18)
plt.xlabel('Δν (cm⁻¹)', fontsize=18)

def R1_0(R1_0_value):
R1_0 = (float(R1_0_box.value[0:-3]))
initialise2()

def V1_0(V1_0_value):
V1_0 = (float(V1_0_box.value[0:-5]))
initialise2()

def get_boxes():
R1_0   = (float(R1_0_box.value[0:-3]))
V1_0   = (float(V1_0_box.value[0:-5]))
return (R1_0,V1_0)

def initialise2():
R1_0,V1_0=get_boxes()
ruby_slider.max    = 750
ruby_slider.value  = R1_0
ruby_slider.min    = R1_0
P_slider2.max      = A/B*((1+(ruby_slider.max-R1_0)/R1_0)**B-1)
P_slider2.value    = 0
raman_slider.max   = ((P_slider2.max*(1/0.501))+V1_0)
raman_slider.value = V1_0
raman_slider.min   = V1_0

ruby_dropdown = widgets.Dropdown(options = {'Hydrostatic - Dewaele et al. 2004': 1, 'Non-hydrostatic - Mao et al. 1986': 2},description='RUBY:',layout=Layout(width='35%'))
raman_dropdown = widgets.Dropdown(options = {'Walter et al. 2014': 1},description='RAMAN:',layout=Layout(width='35%'),disabled=True)

R1_0_box = widgets.Text(value='694.2 nm',disabled=False,layout=Layout(width='18%'),description='R1 λ₀:')
V1_0_box = widgets.Text(value='1332 cm⁻¹',disabled=False,layout=Layout(width='18%'),description='D ν₀:')

ruby_slider = widgets.FloatSlider(min=694.2, max=750, step=0.01, value=694.2, description='R1 λ:',layout=Layout(width='52.5%'),continuous_update=False)
ruby_slider.style.handle_color = 'lightblue'
raman_slider = widgets.FloatSlider(min=1332, max=1600, step=0.1, value=1332, description='001 ν:',layout=Layout(width='52.5%'),continuous_update=False)
raman_slider.style.handle_color = 'lightblue'

P_slider2 = widgets.FloatSlider(min=0, max=200, step=0.1, value=0, description='P in GPa:',layout=Layout(width='100%'),disabled=True,continuous_update=False)
P_slider2.style.handle_color = 'lightblue'

w5=widgets.interactive(ruby_scale,scale1=ruby_dropdown)
w6=widgets.interactive(raman_scale,scale2=raman_dropdown)
w7=widgets.interactive(R1_0,R1_0_value=R1_0_box)
w8=widgets.interactive(V1_0,V1_0_value=V1_0_box)
w9=widgets.interactive(ruby,R1=ruby_slider)
w10=widgets.interactive(raman,V1=raman_slider)

initialise2()
intwidget = interactive(cal_plot, i=P_slider2)
intoutput = intwidget.children[-1]
display(VBox([HBox([ruby_dropdown,R1_0_box,ruby_slider]),HBox([raman_dropdown,V1_0_box,raman_slider]),HBox([P_slider2]),HBox([intoutput])]))
intwidget.update()

``````
``````

var element = \$('#c9863146-4d00-42e3-ac16-3b05e5d9fde2');

{"model_id": "a0d75cd7a7874045a84745b7da41878f", "version_major": 2, "version_minor": 0}

``````

# X-ray Energy to Wavelength converter

Convert energy in eV to wavelngth in Å

``````

In [14]:

h = 4.1357e-15
c = 299792458
def energy(e):
wavelength_slider.value=((h*c)/(e*1000))*1e10

def wavelength(w):
energy_slider.value=((h*c)/w)*1e7

energy_slider = widgets.FloatSlider(min=10, max=100, step=0.01, value=1, description='E (KeV)',layout=Layout(width='100%'),continuous_update=False,readout_format='.2f')
energy_slider.style.handle_color = 'lightblue'
wavelength_slider = widgets.FloatSlider(min=0.123985, max=1.23985, step=0.001, value=1.23985, description='λ (Å)',layout=Layout(width='100%'),continuous_update=False,readout_format='.4f')
wavelength_slider.style.handle_color = 'lightblue'

w11=widgets.interactive(energy,e=energy_slider)
w12=widgets.interactive(wavelength,w=wavelength_slider)

display(VBox([HBox([energy_slider]),HBox([wavelength_slider])]))

``````
``````

var element = \$('#baea2a46-d1fc-4c94-9fde-edd85129c19c');

{"model_id": "d91f9cd9cc0b4b949ca2c596a4b67473", "version_major": 2, "version_minor": 0}

``````
``````

In [ ]:

``````