1
+
2
+ # The code below can be used to generate OQMD derived thermodynamic quantities
3
+ # for the Li3-garnets predicted by Aykol, Kim, Hegde and Wolverton (2018).
4
+ # Please note that this code requires the qmpy library, which can be
5
+ # accessed at https://github.com/wolverton-research-group/qmpy and also the OQMD
6
+ # installed locally, per the instructions provided therein. Present authors used the
7
+ # version 1.1 of the database as available for download at oqmd.org/download.
8
+
9
+
10
+ import matplotlib .pyplot as plt
11
+ import numpy as np
12
+ from qmpy import *
13
+
14
+ garnets = Formation .objects .filter (entry__path__contains = 'garnet' )
15
+
16
+ print 'Garnet, formation_energy stability band_gap V_max V_min stable_phases'
17
+
18
+ for garnet in garnets :
19
+
20
+ # Calculating stability with respect to other materials in OQMD within the
21
+ # garnet's chemical space
22
+ space = PhaseSpace ('-' .join (garnet .entry .space ))
23
+ phase_O = Phase (composition = 'O' ,energy = 0 )
24
+ phase_O .energy = - 0.31695794 #298 K -TS of oxygen gas at 1 atm
25
+ space .phase_dict ['O' ] = phase_O
26
+ energy , phases = space .gclp (garnet .entry .name )
27
+ energy = energy / 20.0
28
+ space .clear_all ()
29
+ stability = garnet .delta_e - energy
30
+ if stability > 0.05 :
31
+ continue
32
+
33
+ # COMPUTATION OF BULK VOLTAGE PROFILES
34
+ # Taking a slice of the convex hull from the garnet towards Li.
35
+
36
+ base_comp = str (garnet .entry .name [3 :])
37
+ slice_comp = base_comp + "-Li15" + base_comp
38
+ ps = PhaseSpace (slice_comp )
39
+ phase_O = Phase (composition = 'O' ,energy = 0 )
40
+ phase_O .energy = - 0.31695794
41
+ ps .phase_dict ['O' ] = phase_O
42
+ ps .get_hull ()
43
+
44
+ # List of phases on the convex hull slice
45
+ eq_list = list (ps .hull )
46
+
47
+ # Voltages
48
+ V_list = []
49
+
50
+
51
+ # We keep track of oxygen evolution as well.
52
+ O_x , O_y = [], []
53
+
54
+ # Scanning the sets of equilibrium phases through the slice
55
+ for eq in eq_list :
56
+ energy1 = eq .phases [0 ].energy / eq .phases [0 ].unit_comp ['O' ]* 12.0
57
+ energy2 = eq .phases [1 ].energy / eq .phases [1 ].unit_comp ['O' ]* 12.0
58
+ if 'Li' in eq .phases [0 ].unit_comp :
59
+ x_Li1 = eq .phases [0 ].unit_comp ['Li' ]/ eq .phases [0 ].unit_comp ['O' ]* 12.0
60
+ else :
61
+ x_Li1 = 0
62
+ if 'Li' in eq .phases [1 ].unit_comp :
63
+ x_Li2 = eq .phases [1 ].unit_comp ['Li' ]/ eq .phases [1 ].unit_comp ['O' ]* 12.0
64
+ else :
65
+ x_Li2 = 0
66
+ V = - (energy2 - energy1 )/ (x_Li2 - x_Li1 )
67
+ V_list .append ([x_Li1 ,V ])
68
+ V_list .append ([x_Li2 ,V ])
69
+
70
+ # Check if oxygen is one of the phases (to record evolution).
71
+ for phase in eq .phases [0 ].phase_dict :
72
+ if phase .name == 'O' :
73
+ O_x .append (x_Li1 )
74
+ O_y .append (V )
75
+ for phase in eq .phases [1 ].phase_dict :
76
+ if phase .name == 'O' :
77
+ O_x .append (x_Li2 )
78
+ O_y .append (V )
79
+
80
+ V_list .sort (key = lambda e : e [1 ], reverse = True )
81
+ V_list .sort (key = lambda e : e [0 ])
82
+
83
+ window_V = []
84
+
85
+ # For stable materials, get the voltage window
86
+ # For metastable materials, get the average voltage at x=3.0
87
+ if np .allclose (stability , 0.0 , atol = 0.0001 ):
88
+ for i in range (len (V_list )):
89
+ if np .allclose (V_list [i ][0 ], 3.0 , atol = 0.0001 ):
90
+ window_V .append (V_list [i ][1 ])
91
+ else :
92
+ for i in range (len (V_list )):
93
+ if np .allclose (V_list [i ][0 ], 3.0 , atol = 0.0001 ):
94
+ window_V .append ((V_list [i ][1 ]+ V_list [i + 1 ][1 ])/ 2.0 )
95
+ break
96
+ elif V_list [i ][0 ]> 3.0 :
97
+ window_V .append (V_list [i ][1 ])
98
+ break
99
+
100
+
101
+ x_data , y_data = [], []
102
+
103
+ arrow_y = 3.0
104
+ for i in xrange (len (V_list )):
105
+ x_data .append (V_list [i ][0 ])
106
+ y_data .append (V_list [i ][1 ])
107
+ if V_list [i ][0 ]== 3.0 :
108
+ arrow_y = V_list [i ][1 ]
109
+
110
+ # Plotting the voltage profile
111
+ plt .plot (x_data ,y_data , linewidth = 2.0 , color = 'red' )
112
+ plt .xlabel (r'x in Li$\mathsf{_x}$' + base_comp ,fontsize = 14 )
113
+ plt .ylabel (r'Voltage vs Li/Li+ (V)' ,fontsize = 14 )
114
+ plt .title ('Lix' + base_comp ,fontsize = 14 ,fontweight = 'bold' )
115
+ plt .axis ([0 ,16 ,0 ,5.5 ])
116
+
117
+ # Annotating the garnet composition on the plot
118
+ string = ' ' .join ([garnet .entry .latex ,
119
+ r'$E_g =$ ' , str (garnet .calculation .band_gap ),
120
+ r' eV' ])
121
+ plt .annotate (string , xy = (3.25 , arrow_y + 0.1 ), xytext = (3.6 ,arrow_y + 0.6 ), fontsize = 14 ,
122
+ arrowprops = dict (arrowstyle = "-|>" , relpos = (0.1 , 0. ), fc = 'b' ) )
123
+
124
+ # Find the lowest ooxygen release potential
125
+ O_volts = 1000.0
126
+ i_volts = - 1
127
+ for i in xrange (len (O_y )):
128
+ if O_y [i ] < O_volts :
129
+ i_volts = i
130
+ O_volts = O_y [i ]
131
+
132
+ # Annotate where O is released.
133
+ if i_volts != - 1 :
134
+ plt .annotate (r'$\mathrm{O_2-released}$' , xy = (O_x [i_volts ]+ 0.25 , = O_y [i_volts ]+ 0.1 ), fontsize = 14 ,
135
+ xytext = (O_x [i_volts ]+ 0.6 ,O_y [i_volts ]+ 0.6 ),
136
+ arrowprops = dict (arrowstyle = '-|>' ,fc = 'b' ))
137
+
138
+ plt .tight_layout ()
139
+ plt .savefig ('Li3' + base_comp + '.png' )
140
+ plt .close ()
141
+
142
+ print garnet .entry .name + " {0:.4g}" .format (garnet .delta_e ) \
143
+ + " {0:.4g}" .format (stability ) + " " + str (garnet .calculation .band_gap ) + " " + \
144
+ " {0:.4g}" .format (max (window_V )), " {0:.4g}" .format (min (window_V )), str (phases )
145
+
146
+
147
+ ps .clear_all ()
148
+
149
+ # It is possible to access the structure (POSCAR) or
150
+ # other input files (except POTCARs) as demonstrated below:
151
+
152
+ for i in garnets :
153
+ if i .entry .name == 'Li3Nd3Te2O12' :
154
+ print i .calculation .POSCAR
155
+ print i .calculation .INCAR
0 commit comments