function [w,x,y]=scrum_zsliceuv(cdf,timestep,zdepth)
%  SCRUM_ZSLICE  Returns a matrix containing a horizontal slice of velocity
%          at a specified depth at a given time step from a SCRUM NetCDF 
%          file.  Regions of grid that are shallower than requested value 
%          are returned as NaNs.
%
%       USAGE: [w,x,y]=scrum_zsliceuv(cdf,var,zdepth)
%
%   where zuser is a depth in meters (e.g -10.)
%

% John Evans (joevans@usgs.gov)

if (nargin<2 | nargin>4),
  help scrum_zslice; return
end

ncmex('setopts',0);
ncid=ncmex('open',cdf,'nowrite');
if(ncid==-1),
  disp(['file ' cdf ' not found'])
  return
end

%
% Acquire the grid.
%
% If "lon_rho" and "lat_rho" are present, grab them.
% Otherwise, get "x_rho" and "y_rho".
[lon_rho_varid, rcode] = ncmex('VARID', ncid, 'lon_rho');
[lat_rho_varid, rcode] = ncmex('VARID', ncid, 'lat_rho');
if ( (lon_rho_varid >= 0) | (lat_rho_varid >= 0) )
    x=ncmex('varget',ncid,'lon_rho',[0 0],[-1 -1]);
    y=ncmex('varget',ncid,'lat_rho',[0 0],[-1 -1]);
else
    x=ncmex('varget',ncid,'x_rho',[0 0],[-1 -1]);
    y=ncmex('varget',ncid,'y_rho',[0 0],[-1 -1]);
end

x_rho = x';
y_rho = y';


[eta_rho_length, xi_rho_length] = size(x_rho);
eta_u_length = eta_rho_length;
eta_v_length = eta_rho_length-1;
xi_u_length = xi_rho_length-1;
xi_v_length = xi_rho_length;
eta_psi_length = eta_rho_length-1;
xi_psi_length = xi_rho_length-1;


%
% construct the grids at the psi points.
xtemp = (x_rho(:,1:(xi_rho_length-1)) + x_rho(:,2:xi_rho_length))/2;
x = (xtemp(1:(eta_rho_length-1),:)  + xtemp(2:eta_rho_length,:))/2;
ytemp = (y_rho(:,1:(xi_rho_length-1)) + y_rho(:,2:xi_rho_length))/2;
y = (ytemp(1:(eta_rho_length-1),:)  + ytemp(2:eta_rho_length,:))/2;




%
% Get all the variables needed to compute z.
% The equation is 
%
% z = zeta * (1 + s) + hc*s + (h - hc)*C(s)

[s_rho_dimid, status] = ncmex ( 'dimid', ncid, 's_rho' );
if ( status == -1 )
	fprintf ( 2, 'Could not get s_rho dimid from %s.\n', cdf );
	ncmex ( 'close', ncid );
	return;
end
[dimname, s_rho_length, status] = ncmex ( 'diminq', ncid, s_rho_dimid );
if ( status == -1 )
	fprintf ( 2, 'Could not get s_rho length from %s.\n', cdf );
	ncmex ( 'close', ncid );
	return;
end


[sc_r, status] = ncmex ( 'varget', ncid, 'sc_r', [0], [-1] );
if ( status == -1 )
	fprintf ( 2, 'Could not get ''sc_r'' variable from %s.\n', cdf );
	ncmex ( 'close', ncid );
	return;
end

[zeta, status] = ncmex ( 'varget', ncid, 'zeta', [timestep 0 0], [1 -1 -1] );
zeta = zeta';

[hc_varid, status] = ncmex ( 'varid', ncid, 'hc' );
if ( status == -1 )
	fprintf ( 2, 'Could not get hc variable from %s.\n', cdf );
	ncmex ( 'close', ncid );
	return;
end
[hc, status] = ncmex ( 'varget1', ncid, hc_varid, [0] );
if ( status == -1 )
	fprintf ( 2, 'Could not get hc variable from %s.\n', cdf );
	ncmex ( 'close', ncid );
	return;
end

[h, status] = ncmex ( 'varget', ncid, 'h', [0 0], [-1 -1] );
if ( status == -1 )
	fprintf ( 'scrum_zsliceuv:  could not get ''h'' in %s.', cdf );
	return;
end
h = h';

[Cs_r, status] = ncmex ( 'varget', ncid, 'Cs_r', [0], [-1] );
if ( status == -1 )
	fprintf ( 'scrum_zsliceuv:  could not get ''Cs_r'' in %s.', cdf );
	return;
end



%
% Construct the depth.
n = length(sc_r);
z = [];

% 
% if it looks upside-down, replace with following line 
%for i = n:-1:1
for i = 1:n
	zi = zeta * (1+sc_r(i)) + hc*sc_r(i) + (h - hc)*Cs_r(i);
	z = cat ( 3, z, zi );
end
z = permute ( z, [3 1 2] );
	

%
% Now average z, h, and zeta across the grid cell centers.
z = (z(:,1:eta_rho_length-1,:)+z(:,2:eta_rho_length,:))/2;
z = (z(:,:,1:xi_rho_length-1)+z(:,:,2:xi_rho_length))/2;
h = (h(1:eta_rho_length-1,:)+h(2:eta_rho_length,:))/2;
h = (h(:,1:xi_rho_length-1)+h(:,2:xi_rho_length))/2;
zeta = (zeta(1:eta_rho_length-1,:)+zeta(2:eta_rho_length,:))/2;
zeta = (zeta(:,1:xi_rho_length-1)+zeta(:,2:xi_rho_length))/2;


%
% reshape the depth such that each vertical profile is a column.
z = reshape ( z, [s_rho_length eta_psi_length*xi_psi_length] );



%
% Retrieve u at the given timestep.
[data_u, status] = ncmex ( 'varget', ncid, 'u', [timestep 0 0 0], [1 -1 -1 -1] );
if ( status == -1 )
	fprintf ( 'scrum_zsliceuv:  could not get ''u'' in %s.', cdf );
	return;
end
data_u = permute ( data_u, [3 2 1] );
data_u = (data_u(:,1:eta_u_length-1,:) + data_u(:,2:eta_u_length,:))/2;
data_u = reshape(data_u,[s_rho_length eta_psi_length*xi_psi_length]);

%
% Retrieve v at the given timestep.
if ( status == -1 )
	fprintf ( 'scrum_zsliceuv:  could not get ''u'' in %s.', cdf );
	return;
end
[data_v, status] = ncmex ( 'varget', ncid, 'v', [timestep 0 0 0], [1 -1 -1 -1] );
data_v = permute ( data_v, [3 2 1] );
data_v = (data_v(:,:,1:xi_v_length-1) + data_v(:,:,2:xi_v_length))/2;
data_v = reshape(data_v,[s_rho_length eta_psi_length*xi_psi_length]);


%
% If there is a mask_rho, we will want to use it later.
[mask_rho_varid, status] = ncmex ( 'varid', ncid, 'mask_rho' );
if ( status ~= -1 )
	[mask_rho, status] = ncmex ( 'varget', ncid, 'mask_rho', [0 0], [-1 -1] );
	if ( status == -1 )
		fprintf ( 'scrum_zsliceuv:  could not get ''mask_rho'' in %s.', cdf );
		return;
	end
end

ncmex ( 'close', ncid );





velocity = data_u + sqrt(-1)*data_v;


%
% define z and velocity at zeta (elevation)
z = [z; reshape(zeta, [1 eta_psi_length*xi_psi_length] ) ];
velocity = [velocity; velocity(s_rho_length,:)];

%
% define z at values greater than zeta to be Inf
% define velocity to be NaN
z = [z; Inf*ones(1,eta_psi_length*xi_psi_length)];
velocity = [velocity; NaN * ones(1,eta_psi_length*xi_psi_length)];

%
% define z at bathymetry values to be those bathymetry values
% define velocity at bathymetry values to be same as data at lowest 
% existing values.
z = [ -1*reshape(h,[1 eta_psi_length*xi_psi_length]); z];
velocity = [ velocity(1,:); velocity ];


%
% define z at depth greater than bathymetry to be -Inf
% define velocity at depth greater than bathymetry to be NaN
z = [ -Inf*ones(1,eta_psi_length*xi_psi_length); z ];
velocity = [ NaN * ones(1,eta_psi_length*xi_psi_length); velocity ];



%
% Find the indices of data values that have just greater depth than
% zdepth.
zgreater = ( z < zdepth );
zg_ind = diff(zgreater);
zg_ind = find(zg_ind~=0);
zg_ind = zg_ind + [0:1:length(zg_ind)-1]';
velocity_greater_z = velocity(zg_ind);
depth_greater_z = z(zg_ind);


%
% Find the indices of the data values that have just lesser depth
% than zdepth.
zlesser = ( z > zdepth );
zl_ind = diff(zlesser);
zl_ind = find(zl_ind~=0);
zl_ind = zl_ind + [1:1:length(zg_ind)]';
velocity_lesser_z = velocity(zl_ind);
depth_lesser_z = z(zl_ind);


%
% Interpolate between the data values.
alpha = (zdepth - depth_greater_z) ./ ( depth_lesser_z - depth_greater_z );

velocity_at_depth = (velocity_lesser_z .* alpha) + (velocity_greater_z .* (1-alpha));


%
% Now reshape the data into a square grid.
w = reshape ( velocity_at_depth, [eta_psi_length xi_psi_length] );




w = w.'; x = x.'; y = y.';

% apply the rotation
%
% Since the "angle" variable is not always present, we
% need to construct it.  In the scrum files, it is apparently
% always in degrees.  Don't bother with degrees here.
angle = zeros(size(x));



[r,c] = size(x);
j = [2:c-1];
for i = 2:r-1
    angle(i,j) = atan2(y(i+1,j)-y(i-1,j), x(i+1,j)-x(i-1,j));
end

% rotate into east and north components
 w=w.*exp(sqrt(-1)*angle);


%
% Mask out the land.
% Since we average the u and v across cells, the appropriate mask
% dimension is that of "mask_psi".  I don't want to take the chance
% that it may not be present in the file, so I compute it from 
% mask_rho.
[umask,vmask,pmask]=uvp_masks ( mask_rho );
mask_inds = find ( pmask == 0 );
w(mask_inds) = NaN * ones(size(mask_inds));


