changeset 11592:32011409d879 octave-forge

new newton
author cdf
date Tue, 02 Apr 2013 18:02:58 +0000
parents 4599bf7580aa
children 4b1917e2fa9a
files extra/secs1d/inst/demos/diode_tran_noscale.m extra/secs1d/inst/secs1d_newton.m
diffstat 2 files changed, 342 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/extra/secs1d/inst/demos/diode_tran_noscale.m	Tue Apr 02 12:40:21 2013 +0000
+++ b/extra/secs1d/inst/demos/diode_tran_noscale.m	Tue Apr 02 18:02:58 2013 +0000
@@ -22,7 +22,7 @@
 
 % time span for simulation
 tmin = 0;
-tmax = 3/500;
+tmax = 3/5e3;
 tspan = [tmin, tmax];
 
 Fn = Fp = zeros (size (device.x));
@@ -50,26 +50,26 @@
 
 function fn = vbcs_1 (t);
   fn = [0; 0];
-  fn(2) = 1 * sin (500 * pi * t);
+  fn(2) = - 30 * sin (5e3 * pi * t);
 endfunction
 
 function fp = vbcs_2 (t);
   fp = [0; 0];
-  fp(2) = 1 * sin (500 * pi * t);
+  fp(2) = - 30 * sin (5e3 * pi * t);
 endfunction
 
 vbcs = {@vbcs_1, @vbcs_2};
 
 % tolerances for convergence checks
-algorithm.toll   = 1e-10;
+algorithm.toll   = 1e-3;
 algorithm.ltol   = 1e-10;
 algorithm.maxit  = 100;
 algorithm.lmaxit  = 100;
 algorithm.ptoll  = 1e-12;
 algorithm.pmaxit = 1000;
-algorithm.colscaling = [1 1e23 1e25];
+algorithm.colscaling = [10 1e25 1e25];
 algorithm.rowscaling = [1 1e7 1e7];
-algorithm.maxnpincr  = constants.Vth;
+algorithm.maxnpincr  = 1e-2;
 
 %% initial guess via stationary simulation
 [nin, pin, Vin, Fnin, Fpin, Jn, Jp, it, res] = secs1d_dd_gummel_map_noscale ...
@@ -78,9 +78,16 @@
 %% 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_newton_noscale (device, material, constants, algorithm,
-                                   Vin, nin, pin, Fnin, Fpin, tspan, vbcs);
+[V, n, p, Fn, Fp, Jn, Jp, Itot, tout] = secs1d_newton (device, material, constants, algorithm,
+                                                       Vin, nin, pin, tspan, @vbcs_1);
+
+%[n, p, V, Fn, Fp, Jn, Jp, tout, numit, 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, tout, numit, 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);
@@ -99,8 +106,8 @@
 %## drawnow
 
 vvector  = Fn(end, :);
-ivector  = (Jn(end, :) + Jp(end, :));
+ivector  = Itot (2, :);
 
-plotyy (t, vvector, t, device.W*ivector)
+plotyy (tout, vvector, tout, device.W*ivector)
 drawnow
    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extra/secs1d/inst/secs1d_newton.m	Tue Apr 02 18:02:58 2013 +0000
@@ -0,0 +1,324 @@
+function [V, n, p, Fn, Fp, Jn, Jp, Itot, tout] = secs1d_newton (device, material, constants, algorithm,
+                                                                Vin, nin, pin, tspan, va)  
+  rejected = 0;
+  Nnodes = numel (device.x);
+  dt = (tspan(2) - tspan(1)) / 20;  
+  t(tstep = 1) = tspan (1);
+  [V, n, p] = deal (Vin, nin, pin);
+  M = bim1a_reaction (device.x, 1, 1);
+
+  while (t < tspan(2))
+
+    reject = false;        
+    t = tout(++tstep) = min (t + dt, tspan(2)); 
+    incr0 = 4 * algorithm.maxnpincr;
+
+    [V0, n0, p0] = predict (device, material, constants, algorithm, V, n, p, tstep, tout, va);
+    [V2, n2, p2] = deal (V0, n0, p0);
+
+    for in = 1 : algorithm.maxit
+
+      [V1, n1, p1] = deal (V2, n2, p2);
+
+      res = compute_residual (device, material, constants, algorithm, V2, n2, p2, n2, p2, dt);
+      jac = compute_jacobian (device, material, constants, algorithm, V2, n2, p2, n2, p2, dt);
+      dn = dp = dV = zeros(rows (n) - 2, 1);
+
+      direct = true;
+      if (! direct)
+
+        [dV, dn, dp] = secs1d_block_gaussseidel (algorithm.colscaling(1)*jac{1,1}(2:end-1, 2:end-1)/algorithm.rowscaling(1),
+                                                 algorithm.colscaling(2)*jac{1,2}(2:end-1, 2:end-1)/algorithm.rowscaling(1),
+                                                 algorithm.colscaling(3)*jac{1,3}(2:end-1, 2:end-1)/algorithm.rowscaling(1),
+                                                 algorithm.colscaling(1)*jac{2,1}(2:end-1, 2:end-1)/algorithm.rowscaling(2),
+                                                 algorithm.colscaling(2)*jac{2,2}(2:end-1, 2:end-1)/algorithm.rowscaling(2),
+                                                 algorithm.colscaling(3)*jac{2,3}(2:end-1, 2:end-1)/algorithm.rowscaling(2),
+                                                 algorithm.colscaling(1)*jac{3,1}(2:end-1, 2:end-1)/algorithm.rowscaling(3), 
+                                                 algorithm.colscaling(2)*jac{3,2}(2:end-1, 2:end-1)/algorithm.rowscaling(3), 
+                                                 algorithm.colscaling(3)*jac{3,3}(2:end-1, 2:end-1)/algorithm.rowscaling(3), 
+                                                 - res{1}(2:end-1)/algorithm.rowscaling(1), 
+                                                 - res{2}(2:end-1)/algorithm.rowscaling(2), 
+                                                 - res{3}(2:end-1)/algorithm.rowscaling(3), 
+                                                 algorithm.ltol, algorithm.lmaxit);
+        dV *= algorithm.colscaling(1);
+        dn *= algorithm.colscaling(2);
+        dp *= algorithm.colscaling(3);
+
+      else
+
+        J = [([algorithm.colscaling(1)*jac{1,1}(2:end-1, 2:end-1), algorithm.colscaling(2)*jac{1,2}(2:end-1, 2:end-1), algorithm.colscaling(3)*jac{1,3}(2:end-1, 2:end-1)]/algorithm.rowscaling(1)); 
+             ([algorithm.colscaling(1)*jac{2,1}(2:end-1, 2:end-1), algorithm.colscaling(2)*jac{2,2}(2:end-1, 2:end-1), algorithm.colscaling(3)*jac{2,3}(2:end-1, 2:end-1)]/algorithm.rowscaling(2)); 
+             ([algorithm.colscaling(1)*jac{3,1}(2:end-1, 2:end-1), algorithm.colscaling(2)*jac{3,2}(2:end-1, 2:end-1), algorithm.colscaling(3)*jac{3,3}(2:end-1, 2:end-1)]/algorithm.rowscaling(3))];
+        f = [algorithm.rowscaling(1)\(res{1}(2:end-1)); algorithm.rowscaling(2)\(res{2}(2:end-1)); algorithm.rowscaling(3)\(res{3}(2:end-1))];
+
+        delta = - J \ f;
+
+        dV = delta (1:Nnodes-2)                  * algorithm.colscaling(1);
+        dn = delta (Nnodes-1:2*(Nnodes-2))       * algorithm.colscaling(2);
+        dp = delta (2*(Nnodes-2)+1:3*(Nnodes-2)) * algorithm.colscaling(3);
+
+      endif
+
+      ndv = norm (dV, inf);
+      ndn = norm (dn, inf);
+      ndp = norm (dp, inf);
+      
+      tkv = 1; 
+
+      tkn = 1;
+      where = (n1(2:end-1) + dn <= 0);
+      if (any (where))
+        tkn = .9 * min (n1(2:end-1) ./ abs (dn))
+      endif
+
+      tkp = 1;
+      where = (p1(2:end-1) + dp <= 0);
+      if (any (where))       
+        tkp = .9 * min (p1(2:end-1) ./ abs (dp))
+      endif
+
+      tk = min ([tkv, tkn, tkp])
+      if (tk <= 0)
+        error ("relaxation parameter too small")
+      endif
+      V2(2:end-1) += tk * dV;
+      n2(2:end-1) += tk * dn;
+      p2(2:end-1) += tk * dp;
+
+      if (any (n2 <= 0) || any (p2 <= 0))
+        error ("negative charge density")
+        reject = true; 
+        break;
+      endif
+
+      incr1v = norm (V2 - V1, inf) / (norm (V0, inf) + algorithm.colscaling(1));
+      incr1n = norm (log (n2./n1), inf) / (norm (log (n0), inf) + log (algorithm.colscaling(2)));
+      incr1p = norm (log (p2./p1), inf) / (norm (log (p0), inf) + log (algorithm.colscaling(3)));
+
+      resnlin(in) = incr1 = max ([incr1v, incr1n, incr1p]);
+
+      incr0v = norm (V2 - V0, inf) / (norm (V0, inf) + algorithm.colscaling(1));
+      incr0n = norm (log (n2./n0), inf) / (norm (log (n0), inf) + log (algorithm.colscaling(2)));
+      incr0p = norm (log (p2./p0), inf) / (norm (log (p0), inf) + log (algorithm.colscaling(3)));
+
+      incr0 = max ([incr0v, incr0n, incr0p]);
+        
+      figure (1)
+      semilogy (1:in, resnlin(1:in));
+      drawnow        
+
+      if (incr0 > algorithm.maxnpincr)
+        printf ("newton step too large\n")
+        tstep
+        reject = true;
+        break;
+      endif
+
+      if (incr1 < algorithm.toll)
+        printf ("iteration %d time step %d  convergence reached incr = %g\n", in, tstep, incr1)
+        break;
+      endif
+      
+    endfor %% newton step
+    
+    if (reject)
+
+      ++rejected;
+      printf ("reducing time step\n");
+      t = tout (--tstep)
+      tstep
+      dt /= 2
+
+    else
+
+      Fp(:, tstep) = V2 + constants.Vth * log (p2 ./ device.ni);
+      Fn(:, tstep) = V2 - constants.Vth * log (n2 ./ device.ni);        
+      [V(:, tstep), n(:, tstep), p(:, tstep)] = deal (V2, n2, p2);
+
+      [mobilityn, mobilityp] = compute_mobilities ...
+          (device, material, constants, algorithm, V2, n2, p2);  
+
+      [Jn(:, tstep), Jp(:, tstep)] = compute_currents ...
+          (device, material, constants, algorithm, mobilityn, 
+           mobilityp, V2, n2, p2);
+
+      Itot(:, tstep)  = Jn([1 end], tstep) + Jp([1 end], tstep);
+
+      # Itot(1, tstep) += constants.e0 * material.esir * ...
+      #     ((V(2, tstep) - V(1, tstep)) -
+      #      (V(2, tstep-1) - V(1, tstep-1))) / ...
+      #     (device.x(2) - device.x(1));
+
+      # Itot(2, tstep) += constants.e0 * material.esir * ...
+      #     ((V(end, tstep) - V(end-1, tstep)) -
+      #      (V(end, tstep-1) - V(end-1, tstep-1))) / ...
+      #     (device.x(end) - device.x(end-1));
+      
+      Itot(:, tstep) *= device.W;
+
+      figure (2)
+      plot (tout, Itot);
+      drawnow
+
+      dt *= .5 * sqrt (algorithm.maxnpincr / incr0)
+
+    endif
+      
+  endwhile %% time step
+  printf ("total number of rejected time steps: %d\n", rejected)
+endfunction
+
+function res = compute_residual ...
+      (device, material, constants, algorithm, V, n, p, n0, p0, dt)
+
+  Nnodes    = numel (device.x);
+  Nelements = Nnodes - 1;
+
+  [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);
+
+  epsilon = material.esi * ones (Nelements, 1);
+  
+  A11 = bim1a_laplacian (device.x, epsilon, 1);
+  res{1} = A11 * V + bim1a_rhs (device.x, 1, constants.q * (n - p - device.D));
+
+  A22 = bim1a_advection_diffusion ...
+      (device.x, mobilityn * constants.Vth, 1, 1, V / constants.Vth);
+  res{2} = A22 * n + bim1a_rhs (device.x, 1, (Rn  + 1/dt) .* n - (Gn + n0 * 1/ dt));
+
+  A33 = bim1a_advection_diffusion ...
+      (device.x, mobilityp * constants.Vth , 1, 1, - V / constants.Vth);
+  res{3} = A33 * p + bim1a_rhs (device.x, 1, (Rp + 1/dt) .* p - (Gp + p0 * 1/ dt));
+
+endfunction
+
+function jac = compute_jacobian ...
+      (device, material, constants, algorithm, V, n, p, n0, p0, dt)
+
+  Nnodes    = numel (device.x);
+  Nelements = Nnodes - 1;
+
+  [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         = 2./(1./n(2:end) + 1./n(1:end-1));
+  pm         = 2./(1./p(2:end) + 1./p(1:end-1));
+
+  epsilon    = material.esi * ones (Nelements, 1);
+  
+  jac{1,1} = bim1a_laplacian (device.x, epsilon, 1);
+  jac{1,2} = constants.q * bim1a_reaction (device.x, 1, 1);
+  jac{1,3} = -jac{1,2};
+
+  jac{2,1} = - bim1a_laplacian (device.x, mobilityn .* nm, 1);
+  jac{2,2} = bim1a_advection_diffusion ...
+      (device.x, mobilityn * constants.Vth, 1, 1, V / constants.Vth) + ...
+      bim1a_reaction (device.x, 1, Rn + 1/dt);
+  jac{2,3} = bim1a_reaction (device.x, 1, Rp);
+
+  jac{3,1} = bim1a_laplacian (device.x, mobilityp .* pm, 1);
+  jac{3,2} = bim1a_reaction (device.x, 1, Rn);
+  jac{3,3} = bim1a_advection_diffusion ...
+      (device.x, mobilityp * constants.Vth , 1, 1, - V / constants.Vth) + ...
+      bim1a_reaction (device.x, 1, Rp + 1/dt);
+
+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 [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 [V0, n0, p0] = predict (device, material, constants, algorithm, V, n, p, tstep, tout, va)
+
+  if (tstep > 2)
+
+    it = [tstep - 2 : tstep - 1];
+    t  = tout (it);
+    dt = tout (tstep) - tout (tstep - 1);
+
+    Fn(:, 1) = V(:, it(1)) - constants.Vth * log (n(:, it(1)) ./ device.ni);
+    Fn(:, 2) = V(:, it(2)) - constants.Vth * log (n(:, it(2)) ./ device.ni);
+
+    dFndt = diff (Fn, 1, 2) ./ diff (tout(it));
+
+    Fn0 = Fn(:, 2) + dFndt * dt;
+
+  else
+
+    Fn0 = V(:, tstep-1) - constants.Vth * log (n(:, tstep-1) ./ device.ni);
+
+  endif
+
+  n0 = n(:, tstep-1);
+  p0 = p(:, tstep-1);
+
+  Fn0([1 end]) = va (tout (tstep));
+
+  V0 = Fn0 + constants.Vth * log (n0 ./ device.ni);
+
+endfunction
\ No newline at end of file