Beispiel #1
0
    def solve_general(self, ctx, eq, fixed):
        def conc(Ef, numeric_parameters):
            for s in eq.with_dos:
                yield s, s.dos.concentrationv(ctx, s, None, Ef, numeric_parameters=numeric_parameters)
        nfixed = nvalue(fixed)

        def f(Ef, numeric_parameters=True):
            if numeric_parameters:
                charge = nfixed
            else:
                charge = fixed
            for eq, c in conc(Ef, numeric_parameters):
                charge = charge + c*eq.z
            return charge
        bandv = np.asarray([nvalue(ctx.varsOf(s)['Ebandv'])
                            for s in eq.with_dos])
        a = np.amax(bandv)
        b = np.amin(bandv)
        Ef_value = brent(f, a, b, xtol=self.etol, maxiter=50)
        g = f(Ef_value, False)
        if isinstance(g, forward.value):
            raise NotImplementedError('not tested')
            dg = f(forward.seed(Ef_value), True).deriv
            if not isscalar(dg):
                dg = dg.tocsr().diagonal()
            # must create value : (Ef_value, 1/dg*g')
            Ef = custom_function(lambda *args: Ef_value, lambda *args: dg)(g)
        else:
            Ef = Ef_value
        info = dict((id(eq), c) for eq, c in conc(Ef, False))
        return Ef, info
Beispiel #2
0
 def c(self, ctx, eq,  Ef, numeric_parameters=False):
     info = self._load(ctx, eq)
     N0 = info['N0']
     nsigma = info['nsigma']
     Vt = info['Vt']
     if numeric_parameters:
         N0 = nvalue(N0)
         nsigma = nvalue(nsigma)
         Vt = nvalue(Vt)
     return N0 * self.impl.I(np.sqrt(2.) * nsigma, b=-Ef / info['Vt'])
Beispiel #3
0
    def _dvdb_(self, a, b):
        v = self._nevaluate(nvalue(a), nvalue(b), need_value=False, need_db=True,
                            need_d2ab=not isnvalue(a), need_d2bb=not isnvalue(b))

        def _dIdb(a, b):
            return v['db']

        def _dIdb_deriv(args, value):
            yield lambda: v['d2ab']
            yield lambda: v['d2bb']
        return ad.apply(asdifferentiable(_dIdb, _dIdb_deriv), (a, b))
Beispiel #4
0
    def _value_(self, a, b):
        v = self._nevaluate(nvalue(a), nvalue(
            b), need_value=True, need_da=not isnvalue(a), need_db=not isnvalue(b))

        def _I(a, b):
            return v['value']

        def _I_deriv(args, value):
            yield lambda: v['da']
            yield lambda: v['db']
        return ad.apply(asdifferentiable(_I, _I_deriv), (a, b))
Beispiel #5
0
 def Ef(self, ctx, eq):
     c = ctx.varsOf(eq)['c']
     c_raw = c
     c = where(c > self.c_eps, c, self.c_eps)  # avoid NaN
     if self.logger.isEnabledFor(logging.INFO):
         if np.any(nvalue(c_raw) != nvalue(c)):
             self.logger.info(
                 'Ef(%r): clipping c<%r, min(c)=%r' %
                 (eq.prefix, self.c_eps, np.amin(nvalue(c_raw))))
     N0 = self.N0(ctx, eq)
     return ctx.varsOf(eq.thermal)['Vt'] * np.log(c / N0)
Beispiel #6
0
    def dIdb(self, a, b):
        v = self._nevaluate(
            nvalue(a), nvalue(b), need_value=True, need_da=not isnvalue(a), need_db=True, need_d2ab=not isnvalue(a), need_d2bb=not isnvalue(b))
        i = ad.exp(v['value'])

        def _dIdb(a, _):
            return i * v['db']

        def _dIdb_deriv(args, value):
            yield lambda: i * (v['d2ab'] + v['da'] * v['db'])
            yield lambda: i * (v['d2bb'] + v['db'] * v['db'])
        return ad.apply(asdifferentiable(_dIdb, _dIdb_deriv), (a, b))
Beispiel #7
0
 def c(self, ctx, eq, Ef, numeric_parameters=False):
     Ef_raw = Ef
     if self.Ef_max is not None:
         Ef = where(Ef < self.Ef_max, Ef, self.Ef_max)
         if self.logger.isEnabledFor(logging.INFO):
             if np.any(nvalue(Ef) != nvalue(Ef_raw)):
                 self.logger.info(
                     'c(%r): clipping Ef>%r, max(Ef)=%r' %
                     (eq.prefix, self.Ef_max, np.amax(
                         nvalue(Ef_raw))))
     N0 = self.N0(ctx, eq)
     if numeric_parameters:
         N0 = nvalue(N0)
     Vt = ctx.varsOf(eq.thermal)['Vt']
     if numeric_parameters:
         Vt = nvalue(Vt)
     v = Ef / Vt
     if self.c_limit:
         v_raw = v
         v = where(v <= 0., v, 0.)
         if self.logger.isEnabledFor(logging.INFO):
             if np.any(nvalue(v_raw) != nvalue(v)):
                 self.logger.info(
                     'c(%r): clipping Ef/kT>0, max(Ef/kT)=%r' %
                     (eq.prefix, np.amax(
                         nvalue(v_raw))))
     c = exp(v) * N0
     return c
Beispiel #8
0
    def _b_(self, a, v, b0=None):
        b = self._nsolve_b(nvalue(a), nvalue(v), b0=b0)

        def _b(a, v):
            return b

        def _b_deriv(args, value):
            a_, i_ = args
            b = value
            values = self._nevaluate(
                a_, b, need_da=not isnvalue(a), need_db=True)
            dbdI = 1. / values['db']
            yield lambda: -dbdI * values['da']
            yield lambda: dbdI
        return ad.apply(asdifferentiable(_b, _b_deriv), (a, v))
Beispiel #9
0
    def _value(self, a, b):
        v = self._nevaluate(ad.nvalue(a),
                            ad.nvalue(b),
                            need_value=True,
                            need_da=isinstance(a, ad.forward.value),
                            need_db=isinstance(b, ad.forward.value))

        def _I(a, b):
            return v['value']

        def _I_deriv(args, value):
            yield lambda: v['da']
            yield lambda: v['db']

        return ad.custom_function(_I, _I_deriv)(a, b)
Beispiel #10
0
    def _dvdb(self, a, b):
        v = self._nevaluate(ad.nvalue(a),
                            ad.nvalue(b),
                            need_value=False,
                            need_db=True,
                            need_d2ab=isinstance(a, ad.forward.value),
                            need_d2bb=isinstance(b, ad.forward.value))

        def _dIdb(a, b):
            return v['db']

        def _dIdb_deriv(args, value):
            yield lambda: v['d2ab']
            yield lambda: v['d2bb']

        return ad.custom_function(_dIdb, _dIdb_deriv)(a, b)
Beispiel #11
0
 def __init__(self, impl, a, n=1000, k=5):
     super(UnivariateInterpolatedGaussFermi, self).__init__()
     self.a = a
     self.a_max = impl.a_max
     self.I_min = impl.I_min
     self.I_max = impl.I_max
     self.b_min, self.b_max = map(
         lambda b: impl.b(
             a, b), (impl.I_min, impl.I_max))
     self.btab = np.linspace(self.b_min, self.b_max, n)
     _i = impl.I(ad.forward.seed(a), self.btab)
     self.logItab = np.log(ad.nvalue(_i))
     self.dlogIdatab = 1. / ad.nvalue(_i) * _i.gradient.tocsr().todense().A1
     assert np.all(np.diff(self.logItab) > 0)
     self.spline = make_interp_spline(
         self.btab[::-1], self.logItab[::-1], k=k)
     self.daspline = make_interp_spline(
         self.btab[::-1], self.dlogIdatab[::-1], k=k)
Beispiel #12
0
    def dIdb(self, a, b):
        v = self._nevaluate(ad.nvalue(a),
                            ad.nvalue(b),
                            need_value=True,
                            need_da=isinstance(a, ad.forward.value),
                            need_db=True,
                            need_d2ab=isinstance(a, ad.forward.value),
                            need_d2bb=isinstance(b, ad.forward.value))
        i = ad.exp(v['value'])

        def _dIdb(a, _):
            return i * v['db']

        def _dIdb_deriv(args, value):
            yield lambda: i * (v['d2ab'] + v['da'] * v['db'])
            yield lambda: i * (v['d2bb'] + v['db'] * v['db'])

        return ad.custom_function(_dIdb, _dIdb_deriv)(a, b)
Beispiel #13
0
    def _b(self, a, v, b0=None):
        b = self._nsolve_b(ad.nvalue(a), ad.nvalue(v), b0=b0)

        def _b(a, v):
            return b

        def _b_deriv(args, value):
            a_, i_ = args
            b = value
            values = self._nevaluate(a_,
                                     b,
                                     need_da=isinstance(a, ad.forward.value),
                                     need_db=True)
            dbdI = 1. / values['db']
            yield lambda: -dbdI * values['da']
            yield lambda: dbdI

        return ad.custom_function(_b, _b_deriv)(a, v)
Beispiel #14
0
 def load(self, ctx, eq):
     super(Electroneutrality, self).load(ctx, eq)
     if isinstance(ctx.solver, solver.RamoShockleyCalculation):
         return
     fixed = 0
     for s in eq.other:
         fixed = fixed + nvalue(ctx.varsOf(s)['c']) * s.z
     if eq.analytical and not self.force_general:
         Efv, c = self.solve_analytical(ctx, eq, fixed)
     else:
         Efv, c = self.solve_general(ctx, eq, fixed)
     ctx.varsOf(eq)['Efv'] = Efv
     ctx.varsOf(eq)['conc_Ef'] = c
     Ef = -ctx.varsOf(eq.poisson)['potential'] + Efv
     ctx.outputCell([eq, 'Ef'], Ef, unit=ctx.units.eV)
     ctx.outputCell([eq, 'phi'], -Ef, unit=ctx.units.V)
     for s, sc in zip(eq.with_dos, self.with_dos):
         ctx.outputCell([eq, sc.name, 'c'], c[id(s)],
                        unit=ctx.units.concentration)
Beispiel #15
0
 def _get(self, a):
     a = ad.nvalue(a)
     if a.shape:
         if len(a) > 0:
             if np.count_nonzero(a != a[0]) > 0:
                 raise ValueError('a must have all values equal')
             a = a[0]
         else:
             # a is empty: return anything
             if self.d:
                 return next(iter(self.d.values()))
             else:
                 return self._get(0)
     a = float(a)
     u = self.d.get(a, None)
     if u is None:
         u = UnivariateInterpolatedGaussFermi(
             self.impl, np.asarray(a), **self.kwargs)
         self.d[a] = u
     return u
Beispiel #16
0
 def identity(self, x):
     return self.idx, x - ad.nvalue(x)