Source code for openbandparams.iii_v_zinc_blende_strained

#
#   Copyright (c) 2013-2015, Scott J Maddox
#
#   This file is part of openbandparams.
#
#   openbandparams is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published
#   by the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   openbandparams 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 Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with openbandparams.  If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################

from .iii_v_alloy import IIIVAlloy
from .parameter import method_parameter
from .references import arent_1989, vurgaftman_2001


[docs]class IIIVZincBlendeStrained001(IIIVAlloy): ''' The base class for biaxial-strained III-V zinc blende binary alloys grown on a (001) surface. ''' def __init__(self, unstrained, substrate=None, strain_out_of_plane=None): ''' Either ``substrate`` or ``strain_out_of_plane`` must be specified, but not both. Paramters --------- unstrained : IIIVZincBlendeAlloy Unstrained III-V zinc blende alloy substrate : Alloy with ``a`` parameter (default=None) Growth substrate, assumed to have a (001) surface strain_out_of_plane : float (default=None) Out-of-plane strain [dimensionless], which is negative for tensile strain and positive for compressive strain. This is the strain measured by X-ray diffraction (XRD) symmetric omega-2theta scans. ''' if substrate is not None and strain_out_of_plane is None: self.substrate = substrate self._strain_out_of_plane = None name = '{}/{}(001)'.format(unstrained.name, substrate.name) elif strain_out_of_plane is not None: self.substrate = None self._strain_out_of_plane = float(strain_out_of_plane) name = '{} strained {:g}% along [001]'.format(unstrained.name, float(strain_out_of_plane)*100.) else: raise ValueError('Either `substrate` or `strain_out_of_plane` ' 'must be specified, but not both.') self.unstrained = unstrained super(IIIVZincBlendeStrained001, self).__init__(name, unstrained.elements, parameters=None) #TODO: have get_references also search `unstrained` and `substrate`
[docs] def latex(self): if self._strain_out_of_plane is not None: return '{} strained {:g}% along [001]'.format( self.unstrained.latex(), self._strain_out_of_plane*100.) else: return '{}/{}(001)'.format(self.unstrained.latex(), self.substrate.latex())
[docs] def element_fraction(self, element): ''' Returns the fractional concentration of ``element`` with respect to its sublattice. In a III-V binary, the fraction is either 1 if ``element`` is present, or 0 if it is not. ''' return self.unstrained.element_fraction(element)
@method_parameter(dependencies=['a'], units='dimensionless', references=[arent_1989])
[docs] def strain_in_plane(self, **kwargs): ''' Returns the in-plane strain assuming no lattice relaxation, which is positive for tensile strain and negative for compressive strain. ''' if self._strain_out_of_plane is not None: return ((self._strain_out_of_plane / -2.) * (self.unstrained.c11(**kwargs) / self.unstrained.c12(**kwargs) ) ) else: return 1 - self.unstrained.a(**kwargs) / self.substrate.a(**kwargs)
@method_parameter(dependencies=['c12', 'c11', 'strain_in_plane'], units='dimensionless', references=[arent_1989])
[docs] def strain_out_of_plane(self, **kwargs): ''' Returns the out-of-plane strain assuming no lattice relaxation, which is negative for tensile strain and positive for compressive strain. This is the strain measured by X-ray diffraction (XRD) symmetric omega-2theta scans. ''' if self._strain_out_of_plane is not None: return self._strain_out_of_plane else: return (-2 * self.unstrained.c12(**kwargs) / self.unstrained.c11(**kwargs) * self.strain_in_plane(**kwargs) )
@method_parameter(dependencies=['strain_in_plane', 'a'], units='angstrom', references=[arent_1989])
[docs] def substrate_a(self, **kwargs): ''' Returns the substrate's lattice parameter. ''' if self.substrate is not None: return self.substrate.a(**kwargs) else: return (self.unstrained.a(**kwargs) / (1. - self.strain_in_plane(**kwargs)))
@method_parameter(dependencies=['a_c', 'strain_in_plane', 'strain_out_of_plane'], units='eV', references=[arent_1989])
[docs] def CBO_hydrostatic_strain_shift(self, **kwargs): return (self.unstrained.a_c(**kwargs) * (2 * self.strain_in_plane(**kwargs) + self.strain_out_of_plane(**kwargs) ))
@method_parameter(dependencies=['CBO_hydrostatic_strain_shift'], units='eV', references=[arent_1989])
[docs] def CBO_strain_shift(self, **kwargs): return self.CBO_hydrostatic_strain_shift(**kwargs)
@method_parameter(dependencies=['CBO', 'CBO_strain_shift'], units='eV')
[docs] def CBO(self, **kwargs): ''' Returns the strain-shifted conduction band offset (CBO), assuming the strain affects all conduction band valleys equally. ''' return self.unstrained.CBO(**kwargs) + self.CBO_strain_shift(**kwargs)
@method_parameter(dependencies=['CBO_Gamma', 'CBO_strain_shift'], units='eV')
[docs] def CBO_Gamma(self, **kwargs): ''' Returns the strain-shifted Gamma-valley conduction band offset (CBO), assuming the strain affects all conduction band valleys equally. ''' return (self.unstrained.CBO_Gamma(**kwargs) + self.CBO_strain_shift(**kwargs))
@method_parameter(dependencies=['CBO_L', 'CBO_strain_shift'], units='eV')
[docs] def CBO_L(self, **kwargs): ''' Returns the strain-shifted L-valley conduction band offset (CBO), assuming the strain affects all conduction band valleys equally. ''' return (self.unstrained.CBO_L(**kwargs) + self.CBO_strain_shift(**kwargs))
@method_parameter(dependencies=['CBO_X', 'CBO_strain_shift'], units='eV')
[docs] def CBO_X(self, **kwargs): ''' Returns the strain-shifted X-valley conduction band offset (CBO), assuming the strain affects all conduction band valleys equally. ''' return (self.unstrained.CBO_X(**kwargs) + self.CBO_strain_shift(**kwargs))
@method_parameter(dependencies=['Eg', 'Eg_strain_shift'], units='eV')
[docs] def Eg(self, **kwargs): ''' Returns the strain-shifted bandgap, ``Eg``. ''' return self.unstrained.Eg(**kwargs) + self.Eg_strain_shift(**kwargs)
@method_parameter(dependencies=['VBO_hh', 'CBO'], units='eV')
[docs] def Eg_hh(self, **kwargs): ''' Returns the strain-shifted heavy-hole bandgap, ``Eg_hh``. ''' return self.CBO(**kwargs) - self.VBO_hh(**kwargs)
@method_parameter(dependencies=['VBO_lh', 'CBO'], units='eV')
[docs] def Eg_lh(self, **kwargs): ''' Returns the strain-shifted light-hole bandgap, ``Eg_lh``. ''' return self.CBO(**kwargs) - self.VBO_lh(**kwargs)
@method_parameter(dependencies=['CBO_strain_shift', 'VBO_strain_shift'], units='eV', references=[arent_1989])
[docs] def Eg_strain_shift(self, **kwargs): return self.CBO_strain_shift(**kwargs) - self.VBO_strain_shift(**kwargs)
@method_parameter(dependencies=['a_v', 'strain_in_plane', 'strain_out_of_plane'], units='eV', references=[arent_1989])
[docs] def VBO_hydrostatic_strain_shift(self, **kwargs): return (self.unstrained.a_v(**kwargs) * (2 * self.strain_in_plane(**kwargs) + self.strain_out_of_plane(**kwargs) ))
@method_parameter(dependencies=['b', 'strain_in_plane', 'strain_out_of_plane'], units='eV', references=[arent_1989])
[docs] def VBO_uniaxial_strain_shift(self, **kwargs): return (self.unstrained.b(**kwargs) * (self.strain_out_of_plane(**kwargs) - self.strain_in_plane(**kwargs) ))
@method_parameter(dependencies=['VBO_hydrostatic_strain_shift', 'VBO_uniaxial_strain_shift'], units='eV', references=[arent_1989])
[docs] def VBO_hh_strain_shift(self, **kwargs): return -(self.VBO_uniaxial_strain_shift(**kwargs) + self.VBO_hydrostatic_strain_shift(**kwargs))
@method_parameter(dependencies=['VBO_hydrostatic_strain_shift', 'VBO_uniaxial_strain_shift'], units='eV', references=[arent_1989])
[docs] def VBO_lh_strain_shift(self, **kwargs): return (self.VBO_uniaxial_strain_shift(**kwargs) - self.VBO_hydrostatic_strain_shift(**kwargs))
@method_parameter(dependencies=['VBO', 'VBO_hh_strain_shift'], units='eV')
[docs] def VBO_hh(self, **kwargs): return (self.unstrained.VBO(**kwargs) + self.VBO_hh_strain_shift(**kwargs))
@method_parameter(dependencies=['VBO', 'VBO_lh_strain_shift'], units='eV')
[docs] def VBO_lh(self, **kwargs): return (self.unstrained.VBO(**kwargs) + self.VBO_lh_strain_shift(**kwargs))
@method_parameter(dependencies=['VBO_hh', 'VBO_lh'], units='eV')
[docs] def VBO(self, **kwargs): return max(self.VBO_hh(**kwargs), self.VBO_lh(**kwargs))
@method_parameter(dependencies=['VBO_hh_strain_shift', 'VBO_lh_strain_shift'], units='eV')
[docs] def VBO_strain_shift(self, **kwargs): return max(self.VBO_hh_strain_shift(**kwargs), self.VBO_lh_strain_shift(**kwargs))
@method_parameter(dependencies=['Eg_Gamma', 'Delta_SO', 'Ep', 'F'], units='m_e', references=[vurgaftman_2001])
[docs] def meff_e_Gamma(self, **kwargs): ''' Returns the electron effective mass in the Gamma-valley calculated from Eg_Gamma(T), CBO_strain_shift, Delta_SO, Ep and F, assuming the CBO_strain_shift causes warping of the Gamma-valley consistent with Kane's k.p model. Effects on the valance band are not included. TODO: verify that this is a reasonable assumption. ''' Eg = (self.unstrained.Eg_Gamma(**kwargs) + self.CBO_strain_shift(**kwargs)) Delta_SO = self.unstrained.Delta_SO(**kwargs) Ep = self.unstrained.Ep(**kwargs) F = self.unstrained.F(**kwargs) return 1./((1.+2.*F)+(Ep*(Eg+2.*Delta_SO/3.))/(Eg*(Eg+Delta_SO)))