%% Copyright (C) 2004,2007,2008,2009,2010,2011  Carlo de Falco
%%
%% This file is part of:
%%     secs3d - A 3-D Drift--Diffusion Semiconductor Device Simulator 
%%
%%  secs3d 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 2 of the License, or
%%  (at your option) any later version.
%%
%%  secs3d 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 secs3d; If not, see <http://www.gnu.org/licenses/>.
%%
%%  author: Carlo de Falco     <cdf _AT_ users.sourceforge.net>

%  
%  [V,n,p,res,niter] = DDGnlpoisson (mesh,Dsides,Vin,nin,pin,Fnin,Fpin,D,l2,toll,maxit,verbose)
%  solves $$ -\lambda^2 V'' + (n(V,Fn) - p(V,Fp) -D)$$
%

function [V,n,p,res,niter] = DDGnlpoisson (mesh,Dsides,Vin,nin,pin,Fnin,Fpin,D,l2,toll,maxit,verbose)

global DDGNLPOISSON_LAP DDGNLPOISSON_MASS DDG_RHS

%% Set some useful constants
dampit 		= 3;
dampcoeff	= 2;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% convert input vectors to columns
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if columns(D)>rows(D)
  D=D';
end


if columns(nin)>rows(nin)
  nin=nin';
end

if columns(pin)>rows(pin)
  pin=pin';
end

if columns(Vin)>rows(Vin)
  Vin=Vin';
end 

if columns(Fnin)>rows(Fnin)
  Fnin=Fnin';
end 

if columns(Fpin)>rows(Fpin)
  Fpin=Fpin';
end 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% setup FEM data structures
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nodes=mesh.p;
elements=mesh.t;
Nnodes = length(nodes);
Nelements = length(elements);




% Set values of Dirichelet BCs
Dnodes = Ugetnodesonface(mesh,Dsides);
Bc     = zeros(length(Dnodes),1);
% Set list of nodes without Dirichelet BCs
Varnodes = setdiff([1:Nnodes],Dnodes);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% 		initialization:
%% 		we're going to solve
%% 		$$ - \lambda^2 (\delta V)'' +  (\frac{\partial n}{\partial V} - \frac{\partial p}{\partial V})= -R $$
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% set $$ n_1 = nin $$ and $$ V = Vin $$
V = Vin;
Fn = Fnin;
Fp = Fpin;
n = exp(V-Fn);
p = exp(-V+Fp);
n(Dnodes) = nin(Dnodes);
p(Dnodes) = pin(Dnodes);


%%%
%%% Compute LHS matrices
%%%

%% let's compute  FEM approximation of $$ L = -  \frac{d^2}{x^2} $$
if (isempty(DDGNLPOISSON_LAP))
  DDGNLPOISSON_LAP      = Ucomplap (mesh,l2*ones(Nelements,1));
end

%% compute $$ Mv = ( n + p)  $$
%% and the (lumped) mass matrix M
if (isempty(DDGNLPOISSON_MASS))
  DDGNLPOISSON_MASS=Ucompmass2 (mesh,ones(Nnodes,1),ones(Nelements,1));
end
Mv   =  (n + p);
M     = DDGNLPOISSON_MASS*sparse(diag(Mv));%Ucompmass (mesh,Mv);

%%%
%%% Compute RHS vector (-residual)
%%%

%% now compute $$ T0 = \frac{q}{\epsilon} (n - p - D) $$
if (isempty(DDG_RHS))
  DDG_RHS= Ucompconst (mesh,ones(Nnodes,1),ones(Nelements,1));
end
Tv0   = (n - p - D);
T0    = DDG_RHS.*Tv0;%Ucompconst (mesh,Tv0,ones(Nelements,1));

%% now we're ready to build LHS matrix and RHS of the linear system for 1st Newton step
A 		= DDGNLPOISSON_LAP + M;
R 		= DDGNLPOISSON_LAP * V  + T0; 

%% Apply boundary conditions
A (Dnodes,:) = [];
A (:,Dnodes) = [];
R(Dnodes)  = [];

%% we need $$ \norm{R_1} $$ and $$ \norm{R_k} $$ for the convergence test   
normr(1)	=  norm(R,inf);
relresnorm 	= 1;
reldVnorm   = 1;
normrnew	= normr(1);
dV          = V*0;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% START OF THE NEWTON CYCLE
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for newtit=1:maxit
  if verbose
    fprintf(1,'\n newton iteration: %d, reldVnorm = %e\n',newtit,reldVnorm);
  end

  dV(Varnodes) =(A)\(-R);
  
  
  
  %%%%%%%%%%%%%%%%%%
  %% Start of th damping procedure
  %%%%%%%%%%%%%%%%%%
  tk = 1;
  for dit = 1:dampit
    if verbose
      fprintf(1,'\n damping iteration: %d, residual norm = %e\n',dit,normrnew);
    end
    Vnew   = V + tk * dV;
    
    n = exp(Vnew-Fn);
    p = exp(-Vnew+Fp);
    n(Dnodes) = nin(Dnodes);
    p(Dnodes) = pin(Dnodes);
    
    
    %%%
    %%% Compute LHS matrices
    %%%
    
    %% let's compute  FEM approximation of $$ L = -  \frac{d^2}{x^2} $$
    %L      = Ucomplap (mesh,ones(Nelements,1));
    
    %% compute $$ Mv =  ( n + p)  $$
    %% and the (lumped) mass matrix M
    Mv   =  (n + p);
    M     = DDGNLPOISSON_MASS*sparse(diag(Mv));%Ucompmass (mesh,Mv);
    
    %%%
    %%% Compute RHS vector (-residual)
    %%%
    
    %% now compute $$ T0 = \frac{q}{\epsilon} (n - p - D) $$
    Tv0   = (n - p - D);
    T0    = DDG_RHS.*Tv0;%Ucompconst (mesh,Tv0,ones(Nelements,1));
    
    %% now we're ready to build LHS matrix and RHS of the linear system for 1st Newton step
    A 		= DDGNLPOISSON_LAP + M;
    R 		= DDGNLPOISSON_LAP * Vnew  + T0; 
    
    %% Apply boundary conditions
    A (Dnodes,:) = [];
    A (:,Dnodes) = [];
    R(Dnodes)  = [];
    
    %% compute $$ | R_{k+1} | $$ for the convergence test
    normrnew= norm(R,inf);
    
    % check if more damping is needed
    if (normrnew > normr(newtit))
      tk = tk/dampcoeff;
    else
      if verbose
        fprintf(1,'\nexiting damping cycle because residual norm = %e \n',normrnew);
      end		
      break
    end	
  end

  V		   = Vnew;	
  normr(newtit+1)  = normrnew;
  dVnorm           = norm(tk*dV,inf);
  % check if convergence has been reached
  reldVnorm           = dVnorm / norm(V,inf);
  if (reldVnorm <= toll)
    if(verbose)
      fprintf(1,'\nexiting newton cycle because reldVnorm= %e \n',reldVnorm);
    end
    break
  end

end

res = normr;
niter = newtit;

