Mercurial > forge
changeset 11572:cdd6e0bbf196 octave-forge
newton method
author | cdf |
---|---|
date | Mon, 25 Mar 2013 11:04:56 +0000 |
parents | 10f755d08a29 |
children | 383535d6d361 |
files | extra/secs1d/inst/demos/diode_reverse_noscale.m extra/secs1d/inst/demos/diode_tran_noscale.m extra/secs1d/inst/demos/thyristor_tran_noscale.m extra/secs1d/inst/secs1d_dd_newton_noscale.m extra/secs1d/inst/secs1d_tran_dd_newton_noscale.m |
diffstat | 5 files changed, 601 insertions(+), 89 deletions(-) [+] |
line wrap: on
line diff
--- a/extra/secs1d/inst/demos/diode_reverse_noscale.m Sun Mar 24 15:35:39 2013 +0000 +++ b/extra/secs1d/inst/demos/diode_reverse_noscale.m Mon Mar 25 11:04:56 2013 +0000 @@ -25,8 +25,8 @@ device.tn = secs1d_carrier_lifetime_noscale (device.Na, device.Nd, 'n'); % initial guess for n, p, V, phin, phip -V_p = 1; -V_n = 0; +V_p = 0; +V_n = -100; Fp = V_p * (device.x <= xm); Fn = Fp; @@ -45,34 +45,50 @@ V = Fn + constants.Vth * log (n ./ device.ni); % tolerances for convergence checks -algorithm.toll = 1e-10; -algorithm.maxit = 100; -algorithm.ptoll = 1e-12; -algorithm.pmaxit = 1000; +algorithm.toll = 1e-10; +algorithm.maxit = 1000; +algorithm.ptoll = 1e-12; +algorithm.pmaxit = 1000; algorithm.colscaling = [10 1e23 1e23]; algorithm.rowscaling = [1e6 1e23 1e23]; -algorithm.maxnpincr = constants.Vth / 10; +algorithm.maxnpincr = constants.Vth; + % solve the problem using the full DD model -[n, p, V, Fn, Fp, Jn, Jp, it, res] = ... - secs1d_dd_gummel_map_noscale (device, material, - constants, algorithm, - V, n, p, Fn, Fp); +%algorithm.maxit = 1; +%[n, p, V, Fn, Fp, Jn, Jp, it, res] = ... +# secs1d_dd_gummel_map_noscale (device, material, +# constants, algorithm, +# V, n, p, Fn, Fp); +# pause -algorithm.maxit = 1000; -[n_newt, p_newt, V_newt, Fn_newt, Fp_newt, Jn, Jp, it, res] = secs1d_dd_newton_noscale ... +[V, n, p, res, niter] = ... + secs1d_nlpoisson_newton_noscale (device, material, + constants, algorithm, + V, n, p, Fn, Fp); + +[ng, pg, Vg, Fng, Fpg, Jn, Jp, it, res] = secs1d_dd_gummel_map_noscale ... + (device, material, constants, algorithm, V, n, p, Fn, Fp); + +[n, p, V, Fn, Fp, Jn, Jp, it, res] = secs1d_dd_newton_noscale ... (device, material, constants, algorithm, V, n, p, Fn, Fp); + +semilogy (device.x, n, device.x, p, device.x, ng, device.x, pg) +legend ('n', 'p', 'ng', 'pg') +keyboard + % band structure Efn = -Fn; Efp = -Fp; Ec = constants.Vth * log (material.Nc./n) + Efn; Ev = -constants.Vth * log (material.Nv./p) + Efp; -close all + plot (device.x, Efn, device.x, Efp, device.x, Ec, device.x, Ev) + legend ('Efn', 'Efp', 'Ec', 'Ev') axis tight
--- a/extra/secs1d/inst/demos/diode_tran_noscale.m Sun Mar 24 15:35:39 2013 +0000 +++ b/extra/secs1d/inst/demos/diode_tran_noscale.m Mon Mar 25 11:04:56 2013 +0000 @@ -62,33 +62,37 @@ % tolerances for convergence checks algorithm.toll = 1e-6; -algorithm.maxit = 300; +algorithm.maxit = 100; algorithm.ptoll = 1e-12; algorithm.pmaxit = 1000; -algorithm.maxnpincr = constants.Vth / 10; +algorithm.colscaling = [10 1e23 1e23]; +algorithm.rowscaling = [1e6 1e23 1e23]; +algorithm.maxnpincr = constants.Vth; %% initial guess via stationary simulation -[nin, pin, Vin, Fnin, Fpin, Jn, Jp, it, res] = ... - secs1d_dd_gummel_map_noscale (device, material, - constants, algorithm, - V, n, p, Fn, Fp); +[nin, pin, Vin, Fnin, Fpin, Jn, Jp, it, res] = secs1d_dd_gummel_map_noscale ... + (device, material, constants, algorithm, V, n, p, Fn, Fp); %% close all; semilogy (device.x, nin, 'x-', device.x, pin, 'x-'); pause %% (pseudo)transient simulation -[n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... - secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, - Vin, nin, pin, Fnin, Fpin, tspan, vbcs); +% [n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... +% secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, +% Vin, nin, pin, Fnin, Fpin, tspan, vbcs); + + [n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... + secs1d_tran_dd_newton_noscale (device, material, constants, algorithm, + Vin, nin, pin, Fnin, Fpin, tspan, vbcs); dV = diff (V, [], 1); dx = diff (device.x); E = -dV ./ dx; %% band structure -Efn = -Fn; -Efp = -Fp; -Ec = constants.Vth * log (material.Nc ./ n) + Efn; -Ev = -constants.Vth * log (material.Nv ./ p) + Efp; +%% Efn = -Fn; +%% Efp = -Fp; +%% Ec = constants.Vth * log (material.Nc ./ n) + Efn; +%% Ev = -constants.Vth * log (material.Nv ./ p) + Efp; %## figure (1) %## plot (x, Efn, x, Efp, x, Ec, x, Ev) @@ -102,7 +106,7 @@ ivectora = mean (Jn + Jp, 1); area = 150e-6 * 50e-6; figure (1) -plot (vvector, area*ivector, vvector, area*ivectorn, vvector, area*ivectora) +plotyy (t, vvector, t, area*ivector) legend('J_L','J_0') drawnow
--- a/extra/secs1d/inst/demos/thyristor_tran_noscale.m Sun Mar 24 15:35:39 2013 +0000 +++ b/extra/secs1d/inst/demos/thyristor_tran_noscale.m Mon Mar 25 11:04:56 2013 +0000 @@ -74,11 +74,14 @@ vbcs = {@vbcs_1, @vbcs_2}; % tolerances for convergence checks -algorithm.toll = 1e-6; +algorithm.toll = 1e-4; algorithm.maxit = 100; algorithm.ptoll = 1e-12; algorithm.pmaxit = 100; algorithm.maxnpincr = constants.Vth; +algorithm.colscaling = [10 1e23 1e23]; +algorithm.rowscaling = [1e6 1e23 1e23]; +algorithm.maxnpincr = constants.Vth; logplot = @(x) asinh (x/2) / log(10); close all; plot (device.x, logplot (device.D)); @@ -93,12 +96,46 @@ constants, algorithm, V, n, p, Fn, Fp); -close all; semilogy (device.x, nin, 'x-', device.x, pin, 'x-'); pause +close all; semilogy (device.x, nin, 'x-', device.x, pin, 'x-'); +hold on +semilogy (device.x, device.Na, device.x, device.Nd); +hold off +pause + +%% initial guess via (pseudo)transient simulation +[n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... + secs1d_tran_dd_newton_noscale (device, material, constants, algorithm, + Vin, nin, pin, Fn, Fp, tspan, vbcs); + +Vin = V(:, end); +nin = n(:, end); +pin = p(:, end); +Fnin = Fn(:, end); +Fpin = Fp(:, end); -%% (pseudo)transient simulation -[n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... - secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, - Vin, nin, pin, Fn, Fp, tspan, vbcs); +function fn = vbcs_1 (t); + fn = [0; 0]; + fn(2) = -10*t; +endfunction + +function fp = vbcs_2 (t); + fp = [0; 0]; + fp(2) = -10*t; +endfunction + +vbcs = {@vbcs_1, @vbcs_2}; + +%% (pseudo)transient simulation with negative applied volatage +# [n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... +# secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, +# V(:, end), n(:, end), p(:, end), +# Fn(:, end), Fp(:, end), tspan, vbcs); + +[n, p, V, Fn, Fp, Jnneg, Jpneg, t, it, res] = ... + secs1d_tran_dd_newton_noscale (device, material, constants, algorithm, + Vin, nin, pin, + Fnin, Fpin, tspan, vbcs); +vvectorneg = Fn(end, :); function fn = vbcs_1 (t); fn = [0; 0]; @@ -112,33 +149,20 @@ vbcs = {@vbcs_1, @vbcs_2}; -%% (pseudo)transient simulation -[n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... - secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, - V(:, end), n(:, end), p(:, end), - Fn(:, end), Fp(:, end), tspan, vbcs); +%% (pseudo)transient simulation with positive applied volatage +# [n, p, V, Fn, Fp, Jn, Jp, t, it, res] = ... +# secs1d_tran_dd_gummel_map_noscale (device, material, constants, algorithm, +# V(:, end), n(:, end), p(:, end), +# Fn(:, end), Fp(:, end), tspan, vbcs); -dV = diff (V, [], 1); -dx = diff (device.x); -E = -dV ./ dx; - -%% band structure -Efn = -Fn(:, end); -Efp = -Fp(:, end); -Ec = constants.Vth * log (material.Nc ./ n(:, end)) + Efn; -Ev = -constants.Vth * log (material.Nv ./ p(:, end)) + Efp; - -figure (1) -plot (device.x, Efn, device.x, Efp, device.x, Ec, device.x, Ev) -legend ('Efn', 'Efp', 'Ec', 'Ev') -axis tight -drawnow +[n, p, V, Fn, Fp, Jnpos, Jppos, t, it, res] = ... + secs1d_tran_dd_newton_noscale (device, material, constants, algorithm, + Vin, nin, pin, + Fnin, Fpin, tspan, vbcs); -vvector = Fn(end, :); -ivector = (Jn(end, :) + Jp(end, :)); -ivectorn = (Jn(1, :) + Jp(1, :)); +vvectorpos = Fn(end, :); +ivectorpos = (Jnpos(end, :) + Jppos(end, :)); +ivectorneg = (Jnneg(end, :) + Jpneg(end, :)); -figure (2) -plot (vvector, ivector, vvector, ivectorn) -legend('J_L','J_0') -drawnow +plot (vvectorpos, ivectorpos, vvectorneg, ivectorneg) +drawnow \ No newline at end of file
--- a/extra/secs1d/inst/secs1d_dd_newton_noscale.m Sun Mar 24 15:35:39 2013 +0000 +++ b/extra/secs1d/inst/secs1d_dd_newton_noscale.m Mon Mar 25 11:04:56 2013 +0000 @@ -53,52 +53,64 @@ function [n, p, V, Fn, Fp, Jn, Jp, it, res] = secs1d_dd_newton_noscale ... (device, material, constants, algorithm, Vin, nin, pin, Fnin, Fpin) - dampcoeff = 2; Nnodes = numel (device.x); - V = Vin; n = nin; p = pin; [res, jac] = residual_jacobian (device, material, constants, algorithm, V, n, p); - normr(1) = norm (res, inf); - normrnew = normr(1); - for it = 1 : algorithm.maxit delta = - jac \ res; - - tk = 1; - dv = norm (delta(1:Nnodes-2), inf); - if (dv > algorithm.maxnpincr) - tk = algorithm.maxnpincr / dv; + + dv = delta(1:Nnodes-2) * algorithm.colscaling(1); + dn = delta((Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(2); + dp = delta(2*(Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(3); + + ndv = norm (dv, inf); + ndn = norm (dn, inf); + ndp = norm (dp, inf); + + tkv = 1; + if (ndv > algorithm.maxnpincr) + tkv = algorithm.maxnpincr / ndv; endif - Vnew = Vin; - Vnew(2:end-1) = V(2:end-1) + tk * delta(1:Nnodes-2) * algorithm.colscaling(1); - - nnew = nin; - nnew(2:end-1) = n(2:end-1) + tk * delta((Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(2); + tkn = tkv; + [howmuch, where] = min (n(2:end-1) + tkn * dn); + if (howmuch <= 0) + tkn = - .9 * n(2:end-1)(where) / dn(where) + endif - pnew = pin; - pnew(2:end-1) = p(2:end-1) + tk * delta(2*(Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(3); + tkp = tkn; + [howmuch, where] = min (p(2:end-1) + tkp * dp); + if (howmuch <= 0) + tkp = - .9 * p(2:end-1)(where) / dp(where) + endif - - V = Vnew; n = nnew; p = pnew; + tk = min ([tkv, tkn, tkp]) + + V(2:end-1) += tk * dv; + n(2:end-1) += tk * dn; + p(2:end-1) += tk * dp; + [res, jac] = residual_jacobian (device, material, constants, algorithm, V, n, p); - resvec(it) = reldnorm = + ... - norm (delta(1:Nnodes-2), inf) / norm (V, inf) + ... - norm (delta((Nnodes-2)+(1:Nnodes-2)), inf) / norm (n, inf) + ... - norm (delta(2*(Nnodes-2)+(1:Nnodes-2)), inf) / norm (p, inf); + resvec(it) = reldnorm = ... + ndv / norm (V, inf) + ... + ndn / norm (n, inf) + ... + ndp / norm (p, inf); - plotyy ( - 1:it, log10 (resvec), - 1:it+1, log10 (normr) - ) + figure (2) + semilogy (1:it, resvec) drawnow - + + figure (3) + semilogy (device.x, n, device.x, p) + drawnow + pause + if (reldnorm <= algorithm.toll) break endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/secs1d/inst/secs1d_tran_dd_newton_noscale.m Mon Mar 25 11:04:56 2013 +0000 @@ -0,0 +1,456 @@ +%% Copyright (C) 2004-2013 Carlo de Falco +%% +%% This file is part of +%% SECS1D - A 1-D Drift--Diffusion Semiconductor Device Simulator +%% +%% SECS1D 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. +%% +%% SECS1D 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 SECS1D; If not, see <http://www.gnu.org/licenses/>. + +%% Solve the scaled stationary bipolar DD equation system using Newton's method. +%% +%% [n, p, V, Fn, Fp, Jn, Jp, it, res] = secs1d_tran_dd_newton_noscale ... +%% (device, material, constants, algorithm, Vin, nin, pin, Fnin, Fpin, tspan, vbcs) +%% +%% input: +%% device.x spatial grid +%% tspan = [tmin, tmax] time integration interval +%% vbcs = {fhnbc, fpbc} cell aray of function handles to compute applied potentials as a function of time +%% device.{D,Na,Nd} doping profile +%% Vin initial guess for electrostatic potential +%% nin initial guess for electron concentration +%% pin initial guess for hole concentration +%% Fnin initial guess for electron Fermi potential +%% Fpin initial guess for hole Fermi potential +%% material.{u0n, uminn, vsatn, Nrefn} +%% electron mobility model coefficients +%% material.{u0p, uminp, vsatp, Nrefp} +%% hole mobility model coefficients +%% device.ni intrinsic carrier density +%% material.{tn,tp,Cn,Cp,an,ap,Ecritnin,Ecritpin} +%% generation recombination model parameters +%% algorithm.toll tolerance for Gummel iterarion convergence test +%% algorithm.maxit maximum number of Gummel iterarions +%% +%% output: +%% n electron concentration +%% p hole concentration +%% V electrostatic potential +%% Fn electron Fermi potential +%% Fp hole Fermi potential +%% Jn electron current density +%% Jp hole current density +%% it number of Newton iterations performed +%% res total potential increment at each step + +function [n, p, V, Fn, Fp, Jn, Jp, tout, numit, res] = ... + secs1d_tran_dd_newton_noscale (device, material, constants, algorithm, + Vin, nin, pin, Fnin, Fpin, tspan, vbcs) + + rejected = 0; + + V = Vin; n = nin; p = pin; Fn = Fnin; Fp = Fpin; + + Nnodes = numel (device.x); + Nelements = Nnodes -1; + + [mobilityn, mobilityp] = compute_mobilities ... + (device, material, constants, algorithm, V, n, p); + + [Jn, Jp] = compute_currents ... + (device, material, constants, algorithm, mobilityn, + mobilityp, V, n, p); + + tmax = tspan(2); + tmin = tspan(1); + dt = (tmax - tmin) / 2000; %% initial time step + + tstep = 1; + t = tout(tstep) = tmin; + + resist = 1e7 * 1e-3 ^ 2; + + while (t < tmax) + + try + + t = tout(++tstep) = min (t + dt, tmax); + + n0 = n(:, tstep - 1); + p0 = p(:, tstep - 1); + + if (tstep <= 2) + Fn0 = Fn(:,tstep-1); + Fp0 = Fp(:,tstep-1); + else + Fn0 = Fn(:, tstep-2) .* (tout(tstep-1) - t)/(tout(tstep-1) - tout(tstep-2)) + ... + Fn(:, tstep-1) .* (t - tout(:, tstep-2))/(tout(:, tstep-1) - tout(:, tstep-2)); + Fp0 = Fp(:, tstep-2) .* (tout(tstep-1) - t)/(tout(tstep-1) - tout(tstep-2)) + ... + Fp(:, tstep-1) .* (t - tout(:, tstep-2))/(tout(:, tstep-1) - tout(:, tstep-2)); + endif + + Va = vbcs{1} (t); + Jn(:,tstep) = Jn(:,tstep-1); + Jp(:,tstep) = Jp(:,tstep-1); + + Fn0([1 end]) = Va; + Fp0([1 end]) = Va; + + V0 = Fn0 + constants.Vth * log (n0 ./ device.ni); + + nrfnp = 4 * algorithm.maxnpincr; %% initialize so it is not undefined in case of exception + + [V(:,tstep), n(:,tstep), p(:,tstep), Fn(:,tstep), ... + Fp(:,tstep), Jn(:,tstep), Jp(:,tstep), res_, it, nrfnp] =... + __one_step__ (device, material, constants, algorithm, + V0, n0, p0, Fn0, Fp0, Jn(:,tstep), Jp(:,tstep), + n(:, tstep - 1), p(:, tstep - 1), dt); + + # [V_gummel, n_gummel, p_gummel, Fn_gummel, ... + # Fp_gummel, Jn_gummel, Jp_gummel, ~, ~, nrfnp] =... + # __one_gummel_step__ (device, material, constants, algorithm, + # V0, n0, p0, Fn0, Fp0, Jn(:,tstep), Jp(:,tstep), + # n(:, tstep - 1), p(:, tstep - 1), dt); + + # figure(1001) + # plot (device.x, n_gummel ./ n(:,end)) + + # figure(1002) + # plot (device.x, p_gummel ./ p(:,end)) + + # figure(1003) + # plot (device.x, Fp_gummel - Fp(:,end)) + + # figure(1004) + # plot (device.x, Fn_gummel - Fn(:,end)) + + %keyboard + + %assert (nrfnp <= algorithm.maxnpincr) + + figure (1) + plot (tout, (mean (Jn(:, 1:tstep) + Jp(:, 1:tstep), 1))) + drawnow + + res(tstep,1:it) = res_; + printf ("dt incremented by %g\n", .95 * sqrt (algorithm.maxnpincr / nrfnp)) + dt *= .95 * sqrt (algorithm.maxnpincr / nrfnp); + numit(tstep) = it; + + catch + + warning (lasterr) + warning ("algorithm.maxnpincr = %17.17g, nrfnp = %17.17g, dt %17.17g reduced to %17.17g", + algorithm.maxnpincr, nrfnp, dt, dt * .95 * sqrt (algorithm.maxnpincr / nrfnp)) + + dt *= .95 * sqrt (algorithm.maxnpincr / nrfnp); + + t = tout(--tstep); + if (dt < 100*eps) + warning ("secs1d_tran_dd_newton_noscale: minimum time step reached.") + return + endif + rejected ++ ; + + end_try_catch + + endwhile + printf ("number of rejected time steps: %d\n", rejected) + +endfunction + + +function [V, n, p, Fn, Fp, Jn, Jp, res, it, nrfnp] = ... + __one_step__ (device, material, constants, algorithm, + V0, n0, p0, Fn0, Fp0, Jn0, Jp0, n_old, p_old, dt); + + Fnref = Fn = Fn0; + Fpref = Fp = Fp0; + n = n0; + p = p0; + V = V0; + +% [V, n, p] = secs1d_nlpoisson_newton_noscale ... +% (device, material, constants, algorithm, V0, n0, p0, Fn0, Fp0); + + + Jn = Jn0; + Jp = Jp0; + + Nnodes = numel (device.x); + + [res, jac] = residual_jacobian (device, material, constants, + algorithm, V, n, p, n_old, p_old, dt); + + for it = 1 : algorithm.maxit + + delta = - jac \ res; + + dv = delta(1:Nnodes-2) * algorithm.colscaling(1); + dn = delta((Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(2); + dp = delta(2*(Nnodes-2)+(1:Nnodes-2)) * algorithm.colscaling(3); + + ndv = norm (dv, inf); + ndn = norm (dn, inf); + ndp = norm (dp, inf); + + tkv = 1; + if (ndv > constants.Vth) + tkv = constants.Vth / ndv; + endif + + tkn = tkv; + [howmuch, where] = min (n(2:end-1) + tkn * dn); + if (howmuch <= 0) + tkn = - .9 * n(2:end-1)(where) / dn(where); + endif + + tkp = tkn; + [howmuch, where] = min (p(2:end-1) + tkp * dp); + if (howmuch <= 0) + tkp = - .9 * p(2:end-1)(where) / dp(where); + endif + + tk = min ([tkv, tkn, tkp]) + + V(2:end-1) += tk * dv; + n(2:end-1) += tk * dn; + p(2:end-1) += tk * dp; + + [res, jac] = residual_jacobian (device, material, constants, + algorithm, V, n, p, n_old, + p_old, dt); + + resvec(it) = reldnorm = ... + ndv / norm (V, inf) + ... + ndn / norm (n, inf) + ... + ndp / norm (p, inf); + + figure (3) + semilogy (1:it, resvec) + drawnow + + Fp = V + constants.Vth * log (p ./ device.ni); + Fn = V - constants.Vth * log (n ./ device.ni); + nrfnp = max (norm (Fn - Fnref, inf), norm (Fp - Fpref, inf)); + + if (reldnorm <= algorithm.toll) + %|| (it > 5 && nrfnp > algorithm.maxnpincr)) + break + endif + + endfor + + [mobilityn, mobilityp] = compute_mobilities ... + (device, material, constants, algorithm, V, n, p); + + [Jn, Jp] = compute_currents ... + (device, material, constants, algorithm, mobilityn, + mobilityp, V, n, p); + + res = resvec; + +endfunction + +function [Rn, Rp, Gn, Gp, II] = generation_recombination_model ... + (device, material, constants, algorithm, mobilityn, + mobilityp, V, n, p) + + [Rn_srh, Rp_srh, Gn_srh, Gp_srh] = secs1d_srh_recombination_noscale ... + (device, material, constants, algorithm, n, p); + + [Rn_aug, Rp_aug, G_aug] = secs1d_auger_recombination_noscale ... + (device, material, constants, algorithm, n, p); + + Rn = Rn_srh + Rn_aug; + Rp = Rp_srh + Rp_aug; + + Gp = Gn = Gn_srh + G_aug; + + Fp = V + constants.Vth * log (p ./ device.ni); + Fn = V - constants.Vth * log (n ./ device.ni); + + E = -diff (V) ./ diff (device.x); + + [Jn, Jp] = compute_currents ... + (device, material, constants, algorithm, mobilityn, + mobilityp, V, n, p); + + II = secs1d_impact_ionization_noscale ... + (device, material, constants, algorithm, + E, Jn, Jp, V, n, p, Fn, Fp); + +endfunction + + +function [res, jac] = residual_jacobian (device, material, constants, + algorithm, V, n, p, n0, p0, dt) + + %persistent mobilityn mobilityp Rn Rp Gn Gp II + [mobilityn, mobilityp] = compute_mobilities ... + (device, material, constants, algorithm, V, n, p); + + [Rn, Rp, Gn, Gp, II] = generation_recombination_model ... + (device, material, constants, algorithm, mobilityn, + mobilityp, V, n, p); + + nm = (n(2:end) + n(1:end-1)) / 2; + pm = (p(2:end) + p(1:end-1)) / 2; + + Nnodes = numel (device.x); + Nelements = Nnodes - 1; + + epsilon = material.esi * ones (Nelements, 1) / constants.q; + + A11 = bim1a_laplacian (device.x, epsilon, 1); + A12 = bim1a_reaction (device.x, 1, 1); + A13 = - A12; + R1 = A11 * V + bim1a_rhs (device.x, 1, n - p - device.D); + + A21 = - bim1a_laplacian (device.x, mobilityn .* nm, 1); + A22 = bim1a_advection_diffusion ... + (device.x, mobilityn * constants.Vth, 1, 1, V / constants.Vth) + ... + bim1a_reaction (device.x, 1, Rn + 0/dt); + A23 = bim1a_reaction (device.x, 1, Rp); + R2 = A22 * n + bim1a_rhs (device.x, 1, (Rn + 0/dt) .* n - (Gn + n0 * 0/ dt)); + + A31 = bim1a_laplacian (device.x, mobilityp .* pm, 1); + A32 = bim1a_reaction (device.x, 1, Rn); + A33 = bim1a_advection_diffusion ... + (device.x, mobilityp * constants.Vth , 1, 1, - V / constants.Vth) + ... + bim1a_reaction (device.x, 1, Rp + 0/dt); + R3 = A33 * p + bim1a_rhs (device.x, 1, (Rp + 0/dt) .* p - (Gp + p0 * 0/ dt)); + + N1 = algorithm.rowscaling(1); + N2 = algorithm.rowscaling(2); + N3 = algorithm.rowscaling(3); + + M1 = algorithm.colscaling(1); + M2 = algorithm.colscaling(2); + M3 = algorithm.colscaling(3); + + res = [R1(2:end-1)/N1; R2(2:end-1)/N2; R3(2:end-1)/N2]; + + jac = [[A11(2:end-1, 2:end-1)*M1, A12(2:end-1, 2:end-1)*M2, A13(2:end-1, 2:end-1)*M3]/N1; + [A21(2:end-1, 2:end-1)*M1, A22(2:end-1, 2:end-1)*M2, A23(2:end-1, 2:end-1)*M3]/N2; + [A31(2:end-1, 2:end-1)*M1, A32(2:end-1, 2:end-1)*M2, A33(2:end-1, 2:end-1)*M3]/N3]; + +endfunction + +function [Jn, Jp] = compute_currents (device, material, constants, algorithm, + mobilityn, mobilityp, V, n, p, Fn, Fp) + dV = diff (V); + dx = diff (device.x); + + [Bp, Bm] = bimu_bernoulli (dV ./ constants.Vth); + + Jn = constants.q * constants.Vth * mobilityn .* ... + (n(2:end) .* Bp - n(1:end-1) .* Bm) ./ dx; + + Jp = -constants.q * constants.Vth * mobilityp .* ... + (p(2:end) .* Bm - p(1:end-1) .* Bp) ./ dx; + +endfunction + +function [mobilityn, mobilityp] = compute_mobilities ... + (device, material, constants, algorithm, V, n, p) + + Fp = V + constants.Vth * log (p ./ device.ni); + Fn = V - constants.Vth * log (n ./ device.ni); + + E = -diff (V) ./ diff (device.x); + + mobilityn = secs1d_mobility_model_noscale ... + (device, material, constants, algorithm, E, V, n, p, Fn, Fp, 'n'); + + mobilityp = secs1d_mobility_model_noscale ... + (device, material, constants, algorithm, E, V, n, p, Fn, Fp, 'p'); + +endfunction + + +# function [V, n, p, Fn, Fp, Jn, Jp, res, it, nrfnp] = __one_gummel_step__ ... +# (device, material, constants, algorithm, V0, n0, p0, Fn0, +# Fp0, Jn0, Jp0, n_old, p_old, dt); + +# Fnref = Fn = Fn0; +# Fpref = Fp = Fp0; +# n = n0; +# p = p0; +# V = V0; +# Jn = Jn0; +# Jp = Jp0; + +# dx = diff (device.x); +# Nnodes = numel (device.x); +# Nelements = Nnodes -1; + +# for it = 1 : algorithm.maxit + +# [V, n, p] = secs1d_nlpoisson_newton_noscale ... +# (device, material, constants, algorithm, V, n, p, Fn, Fp); + +# [mobilityn, mobilityp] = compute_mobilities ... +# (device, material, constants, algorithm, V, n, p); + +# [Rn, Rp, Gn, Gp, II] = generation_recombination_model ... +# (device, material, constants, algorithm, mobilityn, +# mobilityp, V, n, p); + + +# An = bim1a_advection_diffusion (device.x, mobilityn, constants.Vth, +# 1, V / constants.Vth); +# An += bim1a_reaction (device.x, 1, Rn + 1/dt); +# R = bim1a_rhs (device.x, 1, Gn + n_old / dt) + ... +# bim1a_rhs (device.x, II, 1); + +# n(2:end-1) = An(2:end-1, 2:end-1) \ (R(2:end-1) - +# An(2:end-1, [1 end]) * n([1 end])); +# Fn = V - constants.Vth * log (n ./ device.ni); + +# Ap = bim1a_advection_diffusion (device.x, mobilityp, constants.Vth, +# 1, -V / constants.Vth); +# Ap += bim1a_reaction (device.x, 1, Rp + 1/dt); +# R = bim1a_rhs (device.x, 1, Gp + p_old / dt) + ... +# bim1a_rhs (device.x, II, 1); + + +# p(2:end-1) = Ap(2:end-1, 2:end-1) \ (R(2:end-1) - +# Ap(2:end-1, [1 end]) * p([1 end])); +# Fp = V + constants.Vth * log (p ./ device.ni); + +# [Jn, Jp] = compute_currents ... +# (device, material, constants, algorithm, mobilityn, mobilityp, +# V, n, p, Fn, Fp); + +# nrfn = norm (Fn - Fn0, inf); +# nrfp = norm (Fp - Fp0, inf); + +# nrfnp = max (norm (Fn - Fnref, inf), norm (Fp - Fpref, inf)); + +# nrv = norm (V - V0, inf); +# res(it) = max ([nrfn; nrfp; nrv]); + +# if (res(it) < algorithm.toll +# || (nrfnp > algorithm.maxnpincr)) +# break; +# endif + +# V0 = V; +# p0 = p ; +# n0 = n; +# Fn0 = Fn; +# Fp0 = Fp; + +# endfor + +# endfunction