def nxc_from_PC(self, filt=slice(None)): corr_index = int(self.raw.shape[0] * 0.02) V_PC_ill = self.data()['Voc'][filt] V_PC_dark = np.mean(self.raw['Voc'][:corr_index]) #print(V_PC_dark) del_sigma = self.A * (V_PC_ill - self.C)**2 + self.B * ( V_PC_ill - self.C) - (self.A * (V_PC_dark - self.C)**2 + self.B * (V_PC_dark - self.C)) # Create an instance of a mobility object MOB = Mobility() """ TEMPERATURE DEPENDENCE - OK Here the mobility_sum is calculated using the temperature data input directly from the data file name. """ def nxc_PC(x): return del_sigma / (C.e * self.W * MOB.mobility_sum( Na=self.Na, Nd=self.Nd, temp=self.T, nxc=x)) nxc_guess = del_sigma / (C.e * self.W * MOB.mobility_sum( Na=self.Na, Nd=self.Nd, temp=self.T, nxc=np.ones_like(del_sigma) * 1e15)) nxc = self.find_iteratively(nxc_guess, nxc_PC) return nxc
def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp'])
def _conductance2deltan_model(conductance, Na, Nd, thickness, mobility_sum_author, temp): ''' returns the excess conductance for a sample ''' assert type(mobility_sum_author) == str or mobility_sum_author is None nxc = 1e10 * np.ones(conductance.shape[0]) i = 1 while (i > 0.0001): mobility_sum = Mobility().mobility_sum(nxc=nxc, Na=Na, Nd=Nd, temp=temp, author=mobility_sum_author) _temp = _conductance2deltan_array(conductance, thickness, mobility_sum) # make sure we are not loosing carriers _temp[_temp < 0.] = 0. # ignore points where there are no carriers index = np.nonzero(nxc) i = np.average(abs(_temp[index] - nxc[index]) / nxc[index]) nxc = _temp # return the value return nxc
def nxc_from_PC(self, filt=slice(None)): corr_index = int(self.raw.shape[0]*0.02) V_PC_ill = self.data()['Voc'][filt] V_PC_dark = np.mean(self.raw['Voc'][:corr_index]) #print(V_PC_dark) del_sigma = self.A*(V_PC_ill-self.C)**2 + self.B*(V_PC_ill-self.C) - (self.A*(V_PC_dark-self.C)**2 + self.B*(V_PC_dark-self.C)) MOB = Mobility() def nxc_PC(x): return del_sigma / (C.e * self.W * MOB.mobility_sum(Na=self.Na, Nd=self.Nd, temp=self.T, nxc=x)) nxc_guess = del_sigma / (C.e * self.W * MOB.mobility_sum(Na=self.Na, Nd=self.Nd, temp=self.T, nxc=np.ones_like(del_sigma)*1e15)) nxc = self.find_iteratively(nxc_guess, nxc_PC) return nxc
def _get_available_models(self): ni = NI().available_models() mobility = Mobility().available_models() ionisation = Ion().available_models() B = Radiative().available_models() values = locals() del values['self'] self.available_models = values return self.available_models
def _update_update(self): ''' creates a dictionary that holds the required semiconudctor models for easy calling ''' self.update = { 'ni': NI(material=self.material, author=self.selected_model['ni']).update, 'mobility': Mobility(material=self.material, author=self.selected_model['mobility']).mobility_sum, 'ionisation': Ion(material=self.material, author=self.selected_model['ionisation']). update_dopant_ionisation, 'B': Radiative( material=self.material, author=self.selected_model['B'], )._get_B }
class Conductivity(HelperFunctions): _cal_dts = { 'material': 'Si', 'temp': 300, 'mob_author': None, 'nieff_author': None, 'ionis_author': None, 'dopant': 'boron', 'Na': 1e16, 'Nd': 0, 'nxc': 1e10, 'resistivity': 1. } def __init__(self, **kwargs): self.calculationdetails = kwargs def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp']) self.ni = ni(material=self._cal_dts['material'], author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) self.ion = Ion(material=self._cal_dts['material'], author=self._cal_dts['ionis_author'], ni_author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) def query_used_authors(self): return self.Mob.model, self.ni.model, self.ion.model def _conductivity(self, **kwargs): self.calculationdetails = kwargs self._update_links() Nid, Nia = get_carriers(nxc=0, Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author']) if np.all(Nid > Nia): Nid = self.ion.update_dopant_ionisation( Nid, self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) elif np.all(Nia > Nid): Nia = self.ion.update_dopant_ionisation( Nia, nxc=self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) ne, nh = get_carriers(Na=Nia, Nd=Nid, nxc=self._cal_dts['nxc'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author']) mob_e = self.Mob.electron_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd']) mob_h = self.Mob.hole_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd']) print(mob_e[-1], mob_h[-1]) return const.e * (mob_e * ne + mob_h * nh) def calculate(self, **kwargs): ''' calculates the conductivity ''' self._cal_dts['conductivity'] = self._conductivity(**kwargs) return self._cal_dts['conductivity']
class DarkConductivity(HelperFunctions): ''' A class for the special case for a sample where the number of excess carriers is zero. It allows caculation of conudtance of doping, and doping from conductance. ''' _cal_dts = { 'material': 'Si', 'temp': 300, 'mob_author': None, 'nieff_author': None, 'ionis_author': None, 'dopant_type': 'p', 'nxc': 1, 'dark_resistivity': 1. } def __init__(self, **kwargs): self.calculationdetails = kwargs self._update_links() def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp']) def query_used_authors(self): return self.Mob.model, self.ni.model, self.ion.model def dark_resistivity2doping(self, dark_resistivity, **kwargs): ''' cacluate the number of ionised dopoants given the resistivity of the sample in the dark ''' return self.dark_conductivity2doping(1. / dark_resistivity, **kwargs) def dark_conductivity2doping(self, dark_conductivity, **kwargs): ''' cacluate the number of ionised dopoants given the conductivity of the sample in the dark Inputs: dark_conductivity: (float) The conductivty of the sample in the dark **kwargs: (optional) Any of the values found in cal_dts Ouput: doping: (float) The substitutional doping density. ''' if bool(kwargs): self.calculationdetails = kwargs self._update_links() mob_e = self.Mob.electron_mobility(nxc=1, Na=0, Nd=0, temp=self._cal_dts['temp']) # # get an inital guess Na = dark_conductivity / const.e / mob_e cond = Conductivity(**self._cal_dts) def cal_dop(N, dopant_type, dark_conductivity): if dopant_type == 'p': Na = N Nd = 0 elif dopant_type == 'n': Na = 0 Nd = N condv = (cond.calculate(Na=Na, Nd=Nd)) return condv - dark_conductivity dop = (opt.newton( cal_dop, x0=Na, tol=0.001, args=(self._cal_dts['dopant_type'], dark_conductivity), )) return dop
class Conductivity(BaseModelClass): ''' Calculates the conductivity of a semiconductor given the inputs inputs 1. material: (str) The elemental name for the material. Defualt (Si) 2. temp: (float) The temperature of the material in Kelvin (300) 3. mob_author: (str) The mobility author to be used 4. nieff_author (str) The intrinsic carrier density to be used 5. ionis_author (str) The author of a model to be used for dopant ionisation 6. dopant (str) The elemental name for the dopants 7. nxc: (array like |cm-3|) The number of excess carriers 8. Na: (array like |cm-3|) The number of acceptor dopants 9. Nd: (array like |cm-3|) The number of donar dopants ''' _cal_dts = { 'material': 'Si', 'temp': 300, 'mob_author': None, 'nieff_author': None, 'ionis_author': None, 'dopant': 'boron', 'Na': 1e16, 'Nd': 0, 'nxc': 1e10, 'resistivity': 1. } def __init__(self, **kwargs): self.calculationdetails = kwargs def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp']) self.ni = ni(material=self._cal_dts['material'], author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) self.ion = Ion(material=self._cal_dts['material'], author=self._cal_dts['ionis_author'], ni_author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) def query_used_authors(self): return self.Mob.model, self.ni.model, self.ion.model def _conductivity(self, **kwargs): self.calculationdetails = kwargs self._update_links() Nid, Nia = get_carriers(nxc=0, Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author'] ) if np.all(Nid > Nia): Nid = self.ion.update_dopant_ionisation( N_dop=Nid, nxc=self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) elif np.all(Nia > Nid): Nia = self.ion.update_dopant_ionisation( N_dop=Nia, nxc=self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) ne, nh = get_carriers( Na=Nia, Nd=Nid, nxc=self._cal_dts['nxc'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author'] ) mob_e = self.Mob.electron_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd'] ) mob_h = self.Mob.hole_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd']) return const.e * (mob_e * ne + mob_h * nh) def calculate(self, **kwargs): ''' calculates the conductivity ''' self._cal_dts['conductivity'] = self._conductivity(**kwargs) return self._cal_dts['conductivity']
class Conductivity(HelperFunctions): _cal_dts = { 'material': 'Si', 'temp': 300, 'mob_author': None, 'nieff_author': None, 'ionis_author': None, 'dopant': 'boron', 'Na': 1e16, 'Nd': 0, 'nxc': 1e10, 'resistivity': 1. } def __init__(self, **kwargs): self.calculationdetails = kwargs def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp']) self.ni = ni(material=self._cal_dts['material'], author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) self.ion = Ion(material=self._cal_dts['material'], author=self._cal_dts['ionis_author'], ni_author=self._cal_dts['nieff_author'], temp=self._cal_dts['temp']) def query_used_authors(self): return self.Mob.model, self.ni.model, self.ion.model def _conductivity(self, **kwargs): self.calculationdetails = kwargs self._update_links() Nid, Nia = get_carriers(nxc=0, Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author'] ) if np.all(Nid > Nia): Nid = self.ion.update_dopant_ionisation( N_dop=Nid, nxc=self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) elif np.all(Nia > Nid): Nia = self.ion.update_dopant_ionisation( N_dop=Nia, nxc=self._cal_dts['nxc'], impurity=self._cal_dts['dopant']) ne, nh = get_carriers( Na=Nia, Nd=Nid, nxc=self._cal_dts['nxc'], temp=self._cal_dts['temp'], ni_author=self._cal_dts['nieff_author'] ) mob_e = self.Mob.electron_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd'] ) mob_h = self.Mob.hole_mobility(nxc=self._cal_dts['nxc'], Na=self._cal_dts['Na'], Nd=self._cal_dts['Nd']) return const.e * (mob_e * ne + mob_h * nh) def calculate(self, **kwargs): ''' calculates the conductivity ''' self._cal_dts['conductivity'] = self._conductivity(**kwargs) return self._cal_dts['conductivity']
class DarkConductivity(HelperFunctions): ''' A class for the special case for a sample where the number of excess carriers is zero. It allows caculation of conudtance of doping, and doping from conductance. ''' _cal_dts = { 'material': 'Si', 'temp': 300, 'mob_author': None, 'nieff_author': None, 'ionis_author': None, 'dopant_type': 'p', 'nxc': 1, 'dark_resistivity': 1. } def __init__(self, **kwargs): self.calculationdetails = kwargs self._update_links() def _update_links(self): # setting downstream values, this should change from initalisation # to just updating through the update function self.Mob = Mob(material=self._cal_dts['material'], author=self._cal_dts['mob_author'], temp=self._cal_dts['temp']) def query_used_authors(self): return self.Mob.model, self.ni.model, self.ion.model def dark_resistivity2doping(self, dark_resistivity, **kwargs): ''' cacluate the number of ionised dopoants given the resistivity of the sample in the dark ''' return self.dark_conductivity2doping(1. / dark_resistivity, **kwargs) def dark_conductivity2doping(self, dark_conductivity, **kwargs): ''' cacluate the number of ionised dopoants given the conductivity of the sample in the dark Inputs: dark_conductivity: (float) The conductivty of the sample in the dark **kwargs: (optional) Any of the values found in cal_dts Ouput: doping: (float) The substitutional doping density. ''' if bool(kwargs): self.calculationdetails = kwargs self._update_links() mob_e = self.Mob.electron_mobility(nxc=1, Na=0, Nd=0, temp=self._cal_dts['temp'] ) # # get an inital guess Na = dark_conductivity / const.e / mob_e cond = Conductivity(**self._cal_dts) def cal_dop(N, dopant_type, dark_conductivity): if dopant_type == 'p': Na = N Nd = 0 elif dopant_type == 'n': Na = 0 Nd = N condv = (cond.calculate(Na=Na, Nd=Nd)) return condv - dark_conductivity dop = (opt.newton(cal_dop, x0=Na, tol=0.001, args=(self._cal_dts['dopant_type'], dark_conductivity),)) return dop