function clm = uvz_from_clim_stdlev(clm,pref,hmean)
% Compute u,v geostrophic from a standard level t,s,ssh climatology
%
% clm = uvz_from_clim_stdlev(clm,pref)
%
% Inputs:
%
%    clm = structure of 3D gridded (stdlev) temperature and salinity
%          clm.temp [time z lat lon]
%          clm.salt [time z lat lon]
%          clm.lon
%          clm.lat
%          clm.z [z(1) is assumed to be the deepest level]
%       optional:
%          clm.zeta [time lat lon]
%
%    pref = reference pressure (db) to compute dynamic height from
%    hmean = constant value subtracted from zeta before output (e.g. for
%          removing a large scale mean in dynamic height)
%
% Outputs:
%
%    Velocity components added to the climatology structure are 
%    defined on a Arakawa C grid
%          clm.u
%          clm.v
%          clm.h*** is the dynamic height (where *** denotes the 
%              reference pressure used)
%          clm.zeta (if it wasn't provided on input) is the surface 
%              height (h***) with the mean removed
%
% John Wilkin Dec 2000
%
% Copyright (c) 2021 - John L. Wilkin - jwilkin@rutgers.edu
% $Id$

% separate out the data -----------------------------------------------

lon  = clm.lon;
lat  = clm.lat;
z    = clm.z;

if ndims(clm.temp)<4
  ntimes = 1;
else
  ntimes = size(clm.temp,1);
end

tclm(1:ntimes,:,:,:) = clm.temp;
sclm(1:ntimes,:,:,:) = clm.salt;

if nargin < 2
  try
    hclm(1:ntimes,:,:) = clm.zeta;
    warning('Found clm.zeta input so using this to reference the flow')
  catch
    warning([lasterr])
    disp(' No pref requested or zeta variable in climatology')
    disp('  Using zeta = 0')
    hclm = zeros([ntimes size(tclm,3) size(tclm,4)]);
  end
end

% ---------------------------------------------------------------------

% allocate the u,v arrays (the geostrophic calculation gets v at 
% u-points and u at v-points of a C grid)

uclm = zeros([size(tclm)+[0 0 -1 0]]); 
vclm = zeros([size(tclm)+[0 0 0 -1]]);
GA = zeros(size(tclm));

disp('geopotential anomaly') % ----------------------------------------

for mon = 1:ntimes

  disp([' Doing time index ' int2str(mon)])

  for J = 1:size(vclm,3)

    % disp(['  Doing J index ' int2str(J)])
    
    x = lon(J,:);
    temp = squeeze(tclm(mon,:,J,:));
    temp = flipud(temp);
    salt = squeeze(sclm(mon,:,J,:));
    salt = flipud(salt);
    pres = flipud(abs(z));

    % geopotential anomaly
    ga = sw_gpan(salt,temp,pres);
    GA(mon,:,J,:) = ga;
    
  end

  if nargin > 1
    
    % compute dynamic height relative to pref    
    dha = GA/9.81; % to get dynamic metres divide by g
  
    % relative to input pref
    l_ref = min(find(pres >= abs(pref)));
    hclm(mon,:,:) = squeeze(dha(mon,l_ref,:,:)-dha(mon,1,:,:));

  end
  
end

disp('v-component of velocity') % -------------------------------------

for mon = 1:ntimes

  disp([' Doing time index ' int2str(mon)])

  for J = 1:size(vclm,3)

    % disp(['  Doing J index ' int2str(J)])

    x = lon(J,:);
    zeta = squeeze(hclm(mon,J,:));

    % geopotential anomaly
    ga = squeeze(GA(mon,:,J,:));
    
    % velocity relative to surface
    velz = sw_gvel(ga,lat(J,:),x);

    % g*zeta for surface
    ga0 = repmat(-9.81*zeta',length(z),1);

    % 'barotropic' velocity
    vel0 = sw_gvel(ga0,lat(J,:),x);

    % total velocity
    vel = vel0 + velz;

    % flip back to fill clm array
    vel = flipud(vel);

    % fill this slice
    vclm(mon,:,J,:) = vel;

  end

end

disp('u-component of velocity') % -------------------------------------

for mon = 1:size(uclm,1)

  disp([' Doing time index ' int2str(mon)])

  for I = 1:size(uclm,4)

    % disp(['  Doing I index ' int2str(I)])
    
    y = lat(:,I);
    zeta = squeeze(hclm(mon,:,I));

    % geopotential anomaly
    ga = squeeze(GA(mon,:,:,I));
     
    % velocity relative to surface
    velz = -sw_gvel(ga,y',lon(:,I));

    % g*zeta for surface
    ga0 = repmat(-9.81*zeta,length(z),1);

    % 'barotropic' velocity
    vel0 = -sw_gvel(ga0,y',lon(:,I));

    % total velocity
    vel = vel0 + velz;
	
    % flip back to fill clm array
    vel = flipud(vel);

    % fill this slice
    uclm(mon,:,:,I) = vel;

  end
end

ArakawaGrid = 'A';

switch ArakawaGrid

  case 'A'
    
    disp('averaging u to Arakawa-A u-points') % ---------------------------
    % and pad extra rows/columns

    M = size(uclm,3);
    Mm = M-1;    
    tmp = 0.5*(uclm(:,:,1:Mm,:)+uclm(:,:,2:M,:));
    uclm = cat(3,tmp(:,:,1,:),tmp,tmp(:,:,Mm,:));
    
    disp('averaging v to Arakawa-A v-points') % ---------------------------
    % and pad extra rows/columns
    
    L = size(vclm,4);
    Lm = L-1;    
    tmp = 0.5*(vclm(:,:,:,1:Lm)+vclm(:,:,:,2:L));
    vclm = cat(4,tmp(:,:,:,1),tmp,tmp(:,:,:,Lm));
    
  case 'C'

    disp('averaging u to Arakawa-C u-points') % ---------------------------
    % and pad extra rows/columns

    M = size(uclm,3);
    Mm = M-1;
    L = size(uclm,4);
    Lm = L-1;
    tmp = 0.25*(uclm(:,:,1:Mm,1:Lm)+uclm(:,:,1:Mm,2:L)+...
	uclm(:,:,2:M,1:Lm)+uclm(:,:,2:M,2:L));
    uclm = cat(3,tmp(:,:,1,:),tmp,tmp(:,:,Mm,:));
    
    disp('averaging v to Arakawa-C v-points') % ---------------------------
    % and pad extra rows/columns
    
    M = size(vclm,3);
    Mm = M-1;
    L = size(vclm,4);
    Lm = L-1;
    tmp = 0.25*(vclm(:,:,1:Mm,1:Lm)+vclm(:,:,1:Mm,2:L)+...
	vclm(:,:,2:M,1:Lm)+vclm(:,:,2:M,2:L));
    vclm = cat(4,tmp(:,:,:,1),tmp,tmp(:,:,:,Lm));
    
end

    
% append results to input clm structure % ---------------------------------

if ntimes == 1
  uclm = squeeze(uclm);
  vclm = squeeze(vclm);
  hclm = squeeze(hclm);
end
  
clm.u = uclm;
clm.v = vclm;
if nargin > 1
  eval(['clm.h' int2str(abs(pref)) ' = hclm;'])
end

if nargin < 3
  clm.zeta = hclm-nanmean(hclm(:));  
else  
  clm.zeta = hclm-hmean;
end

