function phi = fvm_soln_transient_bdry_nodes( X_edges, Z_edges, X_P, Z_P, ...
                                        nt, dt, rho_c_P, K_P, S_C, S_P, ...
                                        phi_0, phi_u, q_d, q_e, q_w )
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  This m-file finds transient phi(x,z), given sources S and
%%  conductivity K_P.  S(x,z) and K_P(x,z) are constant in time.
%%
%%  Main program sets and delivers:
%%    - Mesh geometry (X_P, Z_P, X_edges, Z_edges)
%%    - time-marching info (nt, dt)
%%    - constitutive properties (K_P)
%%    - sources (S_C, S_P)
%%    - initial conditions (phi_0) 
%%    - boundary conditions (phi_u, q_d, q_e, q_w)
%%
%%  Uses Patankar Finite-Volume method.
%%
%%  THIS CODE USES PATANKAR HALF-VOLUMES
%%
%%  Boundary Conditions:
%%  --------------------
%%  At each time step -
%%  vector phi_u is specified value of phi on upper boundary
%%  vector q_w   is specified flux on west boundary
%%  vector q_e   is specified flux on east boundary
%%  vector q_d   is specified flux on down boundary
%%
%%
%%  Initial conditions:
%%  -------------------
%%      phi = phi_0
%%
%%  a_P = coefficient of phi_P at point P = (i,j)
%%  a_E = coefficient of phi_E at point east of (i,j)
%%  a_W, a_U, a_D for points West, Up, Down
%%  a_P_0 = coefficient of phi_P_0, known phi at previous time step
%%
%%  System of equations to be solved for phi
%%
%%       big_A * phi = rhs
%%
%%  big_A = matrix with coefficients a_E etc, modified to include BC
%%  phi   = unknown values in Control-volumes
%%  rhs   = right-hand-side column vector containing sources,
%           initial conditions,and BC terms
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   set time-step partition (for demonstration purposes only!)
%   always use fully implicit scheme (theta=1)
%      theta = 1  fully implicit
%      theta =0.5 Crank-Nicolson
%      theta = 0  explicit
%   ------------------------------------------
    theta = 0.1;


%% INITIALIZING ...
%%%%%%%%%%%%%%%%%%%%

% Geometry
% --------
%
%  get dX, dZ - spacings between finite-volume edges
%  -------------------------------------------------
    dX = diff(X_edges')';
    dZ = diff(Z_edges);
%
%
%  get dX_E, dx_W, dZ_U, dZ_D - 
%          - distances to adjacent volume centers
%  -----------------------------------------------
    dX_e = diff(X_P')';
    % add dummy row at eastern edge to maintain size [nz, nx]
    dX_e = [ dX_e dX_e(:,end) ];
%
    dX_w = diff(X_P')';
 % add dummy row at western edge to maintain size [nz, nx]
    dX_w = [ dX_w(:,1) dX_w ];
%
    dZ_u = diff(Z_P);
 % add dummy row at top edge to maintain size [nz, nx]
    dZ_u = [ dZ_u(1,:)' dZ_u' ]';
%
    dZ_d = diff(Z_P);
 % add dummy row at bottom edge to maintain size [nz, nx]
    dZ_d = [ dZ_d' dZ_d(end,:)' ]';
%
%
%  get f_e, f_w, f_u, f_d 
%          - fractional distances between volume interfaces
%            and adjacent volume centers
%  ---------------------------------------------------
    f_e = ones(size(X_P)) - (X_edges(:,2:end) - X_P)./ dX_e;
%
    f_w = ones(size(X_P)) - (X_P - X_edges(:,1:(end-1)) )./ dX_w;
%
    f_u = ones(size(Z_P)) - (Z_P - Z_edges(1:(end-1),: ))./ dZ_u;
%
    f_d = ones(size(Z_P)) - (Z_edges(2:end,: ) - Z_P)./ dZ_d;
%

%  Conductivities
%%%%%%%%%%%%%%%%%%%
%    If K = K(t), then conductivities need to be calculated 
%    inside time-stepping loop.
%
%  set up matrices for conductivities in adjacent volumes
%  ------------------------------------------------------
    K_E   =  [ K_P(:,2:end) K_P(:, end) ];
    K_W   =  [ K_P(:,1) K_P(:,1:end-1) ];
    K_U   =  [ K_P(1,:)' K_P(1:end-1,:)' ]';
    K_D   =  [ K_P(2:end,:)' K_P(end,:)' ]';
%
%
%  set up interface conductivity matrices
%  ---------------------------------------
    K_e =  1./ ( (1 - f_e)./K_P + f_e./K_E );
    K_w =  1./ ( (1 - f_w)./K_P + f_w./K_W );
    K_u =  1./ ( (1 - f_u)./K_P + f_u./K_U );
    K_d =  1./ ( (1 - f_d)./K_P + f_d./K_D );
%
%
% set up coefficients at adjacent points
% ---------------------------------------
%    If rho_c = rho_c(t), then a_P_0 needs to be calculated 
%    inside time-stepping loop.

    a_E   = (K_e ./ dX_e).* dZ;
    a_W   = (K_w ./ dX_w).* dZ;
    a_U   = (K_u ./ dZ_u).* dX;
    a_D   = (K_d ./ dZ_d).* dX;
    a_P_0 = (rho_c_P./dt).*dX.*dZ;

%
%
  %  plot current solution
        figure(5)
        surf( X_P, Z_P, phi_0 )
        colorbar
        set(gca,'zlim', [ min(min(phi_u)), 0 ] )
        xlabel('Distance  (m)')
        ylabel('Depth  (m)')
        zlabel('Temperature  (^oC)')

 pause


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Time-stepping Loop starts here 
%    (sources and B.C. may be time-dependent)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
     for i_time=1:nt
         
   % set up b matrix - includes constant part of source matrix S 
   %         S = S_C + S_P * phi_P    (units are W m^-3)
   % Boundary-Condition contribution is added below.
   % Initial-Condition contribution must be added at each time step
   %   i.e. b = S_C dX dZ + a_P_0.* T_P_0
   %   Calculated inside time step in case S_C = S_C(t)
%  ---------------------------------------------------------------
    %     b_0 = S_C.* dX.* dZ;
%
%  when using theta < 1, we need old solution at all neighbors
         phi_0_E = [ phi_0(:,2:end) phi_0(:, end) ];
         phi_0_W = [ phi_0(:,1) phi_0(:,1:end-1) ];
         phi_0_U = [ phi_0(1,:)' phi_0(1:end-1,:)' ]';
         phi_0_D = [ phi_0(2:end,:)' phi_0(end,:)' ]';

%         
  %  put initial condition (for this time step) into b
     %%    b = S_C.* dX.* dZ + a_P_0 .* phi_0;
         b = S_C.* dX.* dZ + ( 1 - theta ) * ...
            (a_E.*phi_0_E + a_W.*phi_0_W + a_U.*phi_0_U + a_D.*phi_0_D) ...
           + (a_P_0 - (1 - theta) * (a_E + a_W + a_U + a_D) ).* phi_0;
%

%
%
   % set up coefficient at central point P 
   %   (includes S_P for source dependence on phi(t) )
   %   Calculated inside time step in case S_P = S_P(t)
   % ----------------------------------------------------
      %%   a_P = a_E + a_W + a_U + a_D + a_P_0 - S_P.* dX.* dZ; 
         a_P = theta * (a_E + a_W + a_U + a_D) + a_P_0 - S_P.* dX.* dZ; 
%
%
   %  set Boundary Conditions
   %%%%%%%%%%%%%%%%%%%%%%%%%%%
     %  Since all coefficients have been initialized with
     %  matrix operations assuming all points are interior points,
     %  the coefficients for boundary points must now be updated to 
     %  correctly incorporate B.C.s.
%
   %  specified flux boundaries
   %  ---------------------------
   %   Boundary treatment recommended by Patankar (p. 50) 
   %   half-volumes at domain edges
   %        boundaries are at solution points X_B = X_P
   %   ------------------------------------------------
%
   %  Specified phi
   %  -------------
   %   Boundaries are at solution points X_P (Patankar)
   %   half-volumes at domain edges
   %    Set boundary-point coefficient to unity, b to specified value,
   %    zero out coefficients on neighboring points
   %
%
%

   %   East boundary - outward flux  (x is positive outward)
   %   =====================================================
     %  include specified boundary flux q_e in b
     %  remove a_E from a_P
    %%     a_P(:,end) = a_P(:,end) - a_E(:,end); 
         a_P(:,end) = a_P(:,end) - theta * a_E(:,end); 
         b(:,end) = b(:,end) - q_e(:,i_time).* dZ(:,end);
%
   %  eliminate fictitious East point (outside domain)
         a_E(:,end) = 0;
%

%   West boundary - zero inward flux (x is positive inward)
%   =======================================================
   %  include specified boundary flux q_w in b
   %  remove a_W from a_P
     %%    a_P(:,1) = a_P(:,1) - a_W(:,1); 
         a_P(:,1) = a_P(:,1) - theta * a_W(:,1); 
%
         b(:,1) = b(:,1) + q_w(:,i_time).* dZ(:,1);
%
   %  eliminate fictitious West point (outside domain)
         a_W(:,1) = 0;
%


%   Bottom - geothermal flux
%   ========================  
   %  include specified boundary flux q_d in b
   %  remove a_D from a_P
      %%   a_P(end,:) = a_P(end,:) - a_D(end,:);
         a_P(end,:) = a_P(end,:) - theta * a_D(end,:);
   %
         b(end,:) = b(end,:) - q_d(i_time,:).* dX(end,:);
%
   %  eliminate fictitious Down point (outside domain)
         a_D(end,:) = 0;
%

%
   %   Upper boundary - specified phi = phi_u(t) 
   %   =========================================
         a_P(1,:) = 1; 
         b(1,:) = phi_u(i_time,:);
         a_U(1,:) = 0; 
         a_E(1,:) = 0;
         a_W(1,:) = 0;
         a_D(1,:) = 0;
%
  %  Now call implicit solver
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%
     %%   phi = solver( a_E, a_W, a_U, a_D, a_P, b );
        phi = solver( theta*a_E, theta*a_W, theta*a_U, theta*a_D, a_P, b );
%
%
  %  Save solution as phi_0 for next time step
        phi_0 = phi;
%
  %  plot current solution
        figure(5)
        if( size(X_P,2) <= 2)
            plot( Z_P(:,1), phi(:,1) )
            grid on;box on;
       %%     set(gca,'ylim', [ min(min(phi_u)), 0 ] )
            set(gca,'ylim', [ min( min(min(phi_u)),-max(max(abs(phi))) ), ...
                             max( 0, max(max(abs(phi))) ) ] )
            xlabel('Depth  (m)')
            ylabel('Temperature  (^oC)')

        else
            surf( X_P, Z_P, phi )
            colorbar
    %%        set(gca,'zlim', [ -30, -10 ] )
            set(gca,'zlim', [ min(min(phi_u)), 0 ] )
            xlabel('Distance  (m)')
            ylabel('Depth  (m)')
            zlabel('Temperature  (^oC)')
        end

 pause
        
        
     end
%
