function yout=oct_t_predic(tim,varargin);
% T_PREDIC Tidal prediction
% YOUT=T_PREDIC(TIM,NAMES,FREQ,TIDECON) makes a tidal prediction
% using the output of T_TIDE at the specified times TIM in decimal 
% days (from DATENUM). Optional arguments can be specified using
% property/value pairs: 
%
%       YOUT=T_PREDIC(...,TIDECON,property,value,...)
%
% Available properties are:
%
%    In the simplest case, the tidal analysis was done without nodal
%    corrections, and thus neither will the prediction. If nodal 
%    corrections were used in the analysis, then it is likely we will
%    want to use them in the prediction too and these are computed 
%    using the latitude, if given.
%
%     'latitude'        decimal degrees (+north) (default: none)
%
%    If the original analysis was >18.6 years satellites are
%    not included and we force that here:
%
%     'anallength'      'nodal' (default)
%                       'full'  For >18.6 years.
%
%    The tidal prediction may be restricted to only some of the 
%    available constituents:
%
%     'synthesis'    0 - Use all selected constituents.  (default)
%                    scalar>0 - Use only those constituents with a SNR
%                               greater than that given (1 or 2 are
%                               good choices).
%
%
%  It is possible to call oct_t_predic without using property names, in
%  which case the assumed calling sequence is
%
%    YOUT=T_PREDIC(TIM,NAMES,FREQ,TIDECON,LATITUDE,SYNTHESIS);
%
%  T_PREDIC can be called using the tidal structure available as an 
%  optional output from T_TIDE
%
%    YOUT=T_PREDIC(TIM,TIDESTRUC,...)
%
%  This is in fact the recommended calling procedure (and required
%  when the analysis results are from series>18.6 years in length)

% R. Pawlowicz 11/8/99
% Version 1.0

% 8/2/03 - Added block processing to generate prediction (to
%          avoid memory overflows for long time series).
% 29/9/04 - small bug with undefined ltype fixed
           
if nargin<2,  % Not enough
  error('Not enough input arguments');
end;

longseries=0;
ltype='nodal';

if isstruct(varargin{1}),
  names=varargin{1}.name;
  freq=varargin{1}.freq;
  tidecon=varargin{1}.tidecon;
  if isfield(varargin{1},'ltype') & strcmp(varargin{1}.ltyp(1:3),'ful'),
    longseries=1;
  end;  
  varargin(1)=[];
else
  if length(varargin)<3,
    error('Not enough input arguments');
  end;
  names=varargin{1};
  freq=varargin{2};
  tidecon=varargin{3};
  varargin(1:3)=[];
end;

lat=[];
synth=0;


k=1;
while length(varargin)>0,
  if ischar(varargin{1}),
    switch lower(varargin{1}(1:3)),
      case 'lat',
         lat=varargin{2};
      case 'syn',
         synth=varargin{2};
      case 'ana',
         if isstr(varargin{2}),
	   ltype=varargin{2};
	   if strcmp(varargin{2}(1:3),'ful'),
	      longseries=1;
	   end;   
	 end;  	 
      otherwise,
         error(['Can''t understand property:' varargin{1}]);
    end;
    varargin([1 2])=[]; 
  else
    switch k,
      case 1,
        lat=varargin{1};
      case 2,
        synth=varargin{1};
      otherwise
        error('Too many input parameters');
     end;
     varargin(1)=[];
  end;
  k=k+1;
end;

% Do the synthesis.        

snr=(tidecon(:,1)./tidecon(:,2)).^2;  % signal to noise ratio
if synth>0,
   I=snr>synth;
   if ~any(I),
     warning('No predictions with this SNR');
     yout=NaN+zeros(size(tim));
     return;
   end;  
   tidecon=tidecon(I,:);
   names=names(I,:);
   freq=freq(I);  
end;    

    
if size(tidecon,2)==4,  % Real time series
  ap=tidecon(:,1)/2.*exp(-i*tidecon(:,3)*pi/180);
  am=conj(ap);
else
  ap=(tidecon(:,1)+tidecon(:,3))/2.*exp( i*pi/180*(tidecon(:,5)-tidecon(:,7)));
  am=(tidecon(:,1)-tidecon(:,3))/2.*exp( i*pi/180*(tidecon(:,5)+tidecon(:,7)));
end;

% Mean at central point (get rid of one point at end to take mean of
% odd number of points if necessary).
jdmid=mean(tim(1:2*fix((length(tim)-1)/2)+1));

if longseries,
  const=t_get18consts;
  ju=zeros(size(freq));
  for k=1:size(names,1),
    inam=strmatch(names(k,:),const.name);
    if length(inam)==1,
      ju(k)=inam;
    elseif length(inam)>1,
      [minf,iminf]=min(abs(freq(k)-const.freq(inam)));
      ju(k)=inam(iminf);
    end;  
  end;  

else
  const=oct_t_getconsts;
  ju=zeros(size(freq));

  % Check to make sure names and frequencies match expected values.

  for k=1:size(names,1),
    ju(k)=strmatch(names(k,:),const.name);
  end;
  %if any(freq~=const.freq(ju)),
  %  error('Frequencies do not match names in input');
  %end;
end;

% Get the astronical argument with or without nodal corrections.  
if ~isempty(lat) & abs(jdmid)>1,				  
  [v,u,f]=oct_t_vuf(ltype,jdmid,ju,lat);				  
elseif abs(jdmid)>1, % a real date				  
  [v,u,f]=oct_t_vuf(ltype,jdmid,ju);				  
else								  
   v=zeros(length(ju),1);					  
   u=v; 							  
   f=ones(length(ju),1);					  
end;								  


ap=ap.*f.*exp(+i*2*pi*(u+v));
am=am.*f.*exp(-i*2*pi*(u+v));


tim=tim-jdmid;

[n,m]=size(tim);
tim=tim(:)';
ntim=length(tim);

nsub=10000; % longer than one year hourly.
for j1=1:nsub:ntim
  j2=min(j1 + nsub - 1,ntim);
  yout(j1:j2)=sum(exp( i*2*pi*freq*tim(j1:j2)*24).*ap(:,ones(1,j2-j1+1)),1)+ ...
              sum(exp(-i*2*pi*freq*tim(j1:j2)*24).*am(:,ones(1,j2-j1+1)),1);
end;
     
yout=reshape(yout,n,m);

  
