function values = readhopspe (strvar,lon,lat,depth,time); % % values = readhopspe (strvar,lon,lat,depth,time); % % This function manages the reading of a HOPS PE file or several % related HOPS PE files. % % ------ % Input: % ------ % % strvar...Usually the string name of the field to read % or a cell array of such strings. On the first % call, the name(s) of the HOPS PE file(s) to read. % lon......The longitude(s) at which the values are sought. % (positive East) % On the first call, lon can, optionally, be a scalar % flag value indicating the allowed vertical extrapolations. % [0] no extrapolations. % [1] only extrapolate up (towards the surface). % [2] extrapolate in both directions. [default] % lat......The latitude(s) at which the values are sought. % (positive North) % depth....The depth(s) at which the values are sought. % (positive down) % time.....The times [year month day hour minute second] % at which the values are sought. % % ------- % Output: % ------- % % values...The values interpolated from the HOPS PE. % % ------ % Usage: % ------ % % Overview: % --------- % % This collection of functions is designed to manage the reading and % interpolation of HOPS PE output in Matlab with most details hidden % from the user. There are 3 basic steps: % % (1) Initialization. A single call opens the PE file(s) and % creates local, static variables. % % (2) Data Extraction. Subsequent calls read the PE file(s) and % interpolate the fields to the requested positions. These % calls may be repeated as many times as the user desires. % % (3) Clean Up. A single call closes the PE file(s) and clears % the local, static variables. % % This functions are designed to work in multiple configurations: % % (1) All data in a single domain and in a single file. % (2) All data in a single domain broken up into 2 files % for size reasons % (3) Data from a set of telescoping nested domains, with % each domain contained in a single file. % (4) Data from a set of telescoping nested domains, with % each domain broken up into 2 files. % % Initialization: % --------------- % % The first call to readhopspe is always just to open the necessary PE % netCDF file(s). Generally, only a single argument is passed in, the % file name(s). % % If a single PE file contains all the data, just pass that name as a % string array: % % readhopspe('pefile.nc'); % % If the information is broken up into 2 files with one containing the % tracer output and the second containing the corresponding velocity % output (same times and grids), pass these in as a cell array of strings % with the tracer file in the first position: % % readhopspe({'Tpefile.nc' 'Vpefile.nc'}); % % If the information comes from a set of L telescoping nested domain, each % of which is contained in a single file, the argument is a cell array of % length 1 containing a cell array of length L of file names: % % readhopspe({{'smallest_pefile.nc' ... 'largest_pefile.nc'}}); % % If the information comes from a set of L telescoping nested domain, each % of which is broken up into 2 files with one containing the tracer output % and the second containing the corresponding velocity output, the argument % is a cell array of length 2 containing cell arrays of length L of file names: % % readhopspe({{'smallest_Tpefile.nc' ... 'largest_Tpefile.nc'} ... % {'smallest_Vpefile.nc' ... 'largest_Vpefile.nc'}}); % % Note that if you wish to limit the vertical extrapolations, a second argument % can be given with any of the above forms (see description of allowed % values in above documentation of lon): % % if ~isempty( readhopspe({{'smallest_Tpe.nc' ... 'largest_Tpe.nc'} ... % {'smallest_Vpe.nc' ... 'largest_Vpe'}}, 1) ) % error ('Unable to successfully open HOPS PE file.'); % end; % % If the file(s) were successfully opened, readhopspe returns the empty set % ([]), otherwise it returns -1. % % Data Extraction: % ---------------- % % On subsequent calls, readhopspe interpolates the requested fields at % the requested positions. The fields are requested in the first % argument (STRVAR). This can be a string for a single field or a cell % array of length (M) of strings for M different fields. Valid names are % % 't' 'temp' 'temperature' % 's' 'salt' 'salinity' % 'c' 'sound speed' 'sound velocity' % 'w' 'vertical velocity' % 'u' 'zonal velocity' % 'v' 'meridional velocity' % % For each requested field, readhopspe interpolates the PE netCDF file(s) % to the requested positions specified in LON, LAT, DEPTH, TIME where % LON, LAT and DEPTH are vectors of length N and TIME is a matrix of % size (N,6). The output of readhopspe is a cell array of length M whose % elements are vectors of length N. % % There are 2 kinds of errors that can occur: % % (1) An invalid field is requested. In this case, the corresponding % element of the cell array is the empty set []. % (2) An out-of-range position is requested. This can occur for a point % outside all domains, a time outside the range of the PE files or % a point under the land mask. In any of these cases, the corresponding % value of the output vector(s) is a NaN. % % Clean Up: % --------- % % When complete finished reading the file(s), call readhopspe with no % arguments to close the files and clear its internal storage. If the file(s) % were successfully closed, readhopspe returns the empty set ([]), otherwise it % returns -1. % % if ~isempty(readhopspe) % error ('Unable to successfully close HOPS PE file.'); % end; % % In the above example, the output of the "clean-up" call is directly tested % and the calling program aborts on error. %------------------------------------------------------------------------------- % Set internal static storage. %------------------------------------------------------------------------------- persistent ncids fnames domdat lndinds timdat xtrflg %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- values = []; %------------------------------------------------------------------------------- % On first call, open file(s) and initialize data. %------------------------------------------------------------------------------- if ((nargin==1) | (nargin==2)) [ncids,fnames,domdat,lndinds,timdat] = inithops (strvar); if isempty(timdat) values = -1; end; if (nargin==1) xtrflg = 2; else xtrflg = lon; end; return; end; %------------------------------------------------------------------------------- % On last call, close file(s) and clean-up. %------------------------------------------------------------------------------- if (nargin==0) values = closhops (ncids,fnames); clear ncids fnames domdat lndinds timdat xtrflg; return; end; %------------------------------------------------------------------------------- % Eliminate some error conditions. %------------------------------------------------------------------------------- if (nargin~=5) disp (' '); disp (['***Error: READHOPS - invalid number (',num2str(nargin), ... ') of input arguments.']); disp (' Valid numbers of input arguments are [0, 1, 5]'); disp (' '); return; end; if isempty(timdat) disp (' '); disp ('***Error: READHOPS - input file was not successfully opened.'); disp (' '); return; end; %------------------------------------------------------------------------------- % Convert position data. %------------------------------------------------------------------------------- [domt,xt,it,yt,jt,zt,tt,domv,xv,iv,yv,jv,zv,tv] = getpepos (lon,lat,depth, ... time,domdat,timdat); %------------------------------------------------------------------------------- % Interpolate requested fields. %------------------------------------------------------------------------------- if iscell(strvar) varnames = strvar; else varnames = {strvar}; end; for nvar = 1:length(varnames) switch upper(varnames{nvar}); case {'T' 'TEMP' 'TEMPERATURE'} values{nvar} = intrppe ('temp',ncids{1},fnames{1},[],domt, ... it,xt,jt,yt,zt,tt,squeeze(domdat(:,3)), ... lndinds{1},xtrflg); case {'S' 'SALT' 'SALINITY'} values{nvar} = intrppe ('salt',ncids{1},fnames{1},[],domt, ... it,xt,jt,yt,zt,tt,squeeze(domdat(:,3)), ... lndinds{1},xtrflg); case {'C' 'SOUND SPEED' 'SOUND VELOCITY'} values{nvar} = intrppe ('sndsp',ncids{1},fnames{1},[],domt, ... it,xt,jt,yt,zt,tt,squeeze(domdat(:,3)), ... lndinds{1},xtrflg); case {'W' 'VERTICAL VELOCITY'} values{nvar} = intrppe ('wvzv',ncids{2},fnames{2},[],domv, ... iv,xv,jv,yv,zv,tv,squeeze(domdat(:,3)), ... lndinds{2},xtrflg); case {'U' 'ZONAL VELOCITY'} values{nvar} = intrppe ('vtot',ncids{2},fnames{2},1,domv, ... iv,xv,jv,yv,zv,tv,squeeze(domdat(:,3)), ... lndinds{2},xtrflg); case {'V' 'MERIDIONAL VELOCITY'} values{nvar} = intrppe ('vtot',ncids{2},fnames{2},2,domv, ... iv,xv,jv,yv,zv,tv,squeeze(domdat(:,3)), ... lndinds{2},xtrflg); otherwise values{nvar} = []; end; end; return; %=============================================================================== function [ncids,fnames,domdat,lndinds,timdat] = inithops (strvar); % % [ncids,fnames,domdat,lndinds,timdat] = inithops (strvar); % % This function opens the HOPS PE netCDF file(s) and reads initial data. % % ------ % Input: % ------ % % strvar....Either name of HOPS PE netCDF file or cell array % of names of 2 HOPS PE netCDF files. % % ------- % Output: % ------- % % ncids.....Cell array of netCDF identifiers to open files. % NCIDS{1} - netCDF identifer for tracer file. % NCIDS{2} - netCDF identifer for velocity file. % Can be same as tracer file. % fnames....Cell array of input file names. % FNAMES{1} - name of tracer file. % FNAMES{2} - name of velocity file. % Can be same as tracer file. % domdat....Vector of domain definition data. % DOMDAT( 1) - COORD. Coordinate definition. % DOMDAT( 2) - NX. Number grid points in X-direction. % DOMDAT( 3) - NY. Number grid points in Y-direction. % DOMDAT( 4) - DX. Grid spacing in X-direction. % DOMDAT( 5) - DY. Grid spacing in Y-direction. % DOMDAT( 6) - LONC. Longitude of transformation center. % DOMDAT( 7) - LATC. Latitude of transformation center. % DOMDAT( 8) - DELX. Transformation-Grid offset, X-direction. % DOMDAT( 9) - DELY. Transformation-Grid offset, Y-direction. % DOMDAT(10) - THETA. Rotation angle. % lndinds...Cell array of arrays of land indices. % LNDINDS(1) - TLNDIND. Land indices on tracer grid. % LNDINDS(2) - VLNDIND. Land indices on velocity grid. % timdat....Array to time data. % TIMDAT(1) - TIMEOFF. Initialzation time offset for datenum. % TIMDAT(2) - TIMEND. Last day of PE output. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- ncids = []; fnames = []; domdat = []; lndinds = []; timdat = []; %------------------------------------------------------------------------------- % Open file(s). %------------------------------------------------------------------------------- if isstr(strvar) %--------------------------- %--- Single netCDF file. --- %--------------------------- tfile{1} = strvar; nctid{1} = netcdf(tfile{1}); if isempty(nctid{1}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),tfile{1},setstr(34)]); disp (' '); return; end; vfile = tfile; ncvid = nctid; elseif isstr(strvar{1}) %------------------------- %--- Two netCDF files. --- %------------------------- tfile{1} = strvar{1}; vfile{1} = strvar{2}; nctid{1} = netcdf(tfile{1}); if isempty(nctid{1}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),tfile{1},setstr(34)]); disp (' '); return; end; ncvid{1} = netcdf(vfile{1}); if isempty(ncvid{1}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),vfile{1},setstr(34)]); disp (' '); return; end; elseif (length(strvar)==1) %--------------------------------------- %--- Single chain of nested domains. --- %--------------------------------------- ndoms = length(strvar{1}); tfile = strvar{1}; for n = 1:ndoms nctid{n} = netcdf(tfile{n}); if isempty(nctid{n}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),tfile{n},setstr(34)]); disp (' '); return; end; end; vfile = tfile; ncvid = nctid; else %--------------------------------------- %--- Double chain of nested domains. --- %--------------------------------------- ndoms = length(strvar{1}); tfile = strvar{1}; vfile = strvar{2}; for n = 1:ndoms nctid{n} = netcdf(tfile{n}); if isempty(nctid{n}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),tfile{n},setstr(34)]); disp (' '); return; end; if ~isempty(vfile{n}) ncvid{n} = netcdf(vfile{n}); if isempty(ncvid{n}) disp (' '); disp ('***Error: INITHOPS - unable to open netCDF file:'); disp ([' ',setstr(34),vfile{n},setstr(34)]); disp (' '); return; end; else ncvid{n} = nctid{n}; vfile{n} = tfile{n}; end end; end; ncids = {nctid ncvid}; fnames = {tfile vfile}; %------------------------------------------------------------------------------- % Read domain definition parameters. %------------------------------------------------------------------------------- ndom = length(fnames{1}); domdat = NaN.*ones(ndom,10); timdat = NaN.*ones(ndom,2); for n = 1:ndom [domdatn,tlndindn,vlndindn,timdatn] = ... getpedom (nctid{n},tfile{n},ncvid{n},vfile{n}); domdat(n,:) = domdatn; tlndind{n} = tlndindn; vlndind{n} = vlndindn; timdat(n,:) = timdatn; end; lndinds = {tlndind vlndind}; clear nctid ncvid ndom tfile vfile domdatn tlndindn vlndindn timdatn ... tlndind vlndind return; %=============================================================================== function [domdat,tlndind,vlndind,timdat] = getpedom (nctid,tfile,ncvid,vfile); % % [domdat,tlndind,vlndind,timdat] = getpedom (nctid,tfile,ncvid,vfile); % % This runction reads the spatial/temporal domain parameters from a % HOPS PE netCDF file. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- domdat = []; tlndind = []; vlndind = []; timdat = []; %------------------------------------------------------------------------------- % Set useful constants. %------------------------------------------------------------------------------- cm2m = 0.01; cm2deg = 180.0/(pi*637131500.0); %------------------------------------------------------------------------------- % Determine vintage of PE model. %------------------------------------------------------------------------------- %------------------------ %--- Read PE version. --- %------------------------ peversion = nctid.version(:); %----------------------------------------------------- %--- Convert newer strings to older numeric forms. --- %----------------------------------------------------- if isstr(peversion) pstr = peversion; rmind = find (isletter(pstr) | isspace(pstr)); if ~isempty(rmind) pstr(rmind) = []; end; peversion = str2num(pstr); clear pstr rmind; end; %----------------------------------------------------------- %--- Determine version and release. Technically the --- %--- logic for the release doesn't work since it equates --- %--- the releases for, say, 7.7 and 7.70. --- %----------------------------------------------------------- pever = fix(peversion); perel = round((peversion-pever)*100); clear peversion; %----------------------------------------------------------- %--- Determine vintage. Correct for release logic flaw. --- %----------------------------------------------------------- oldpe = ((pever<7) | ((pever==7) & (perel~=28))); clear pever perel; %------------------------------------------------------------------------------- % Read domain definition parameters. %------------------------------------------------------------------------------- %----------------------------- %--- Coordinate type flag. --- %----------------------------- name = 'coord'; coord = nctid{name}(:); if (isempty(coord) & isempty(nctid{name})) coord = 0; elseif isempty(coord) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; %-------------------- %--- Domain size. --- %-------------------- name = 'tlon'; nx = length(nctid(name)); if isempty(nx) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'tlat'; ny = length(nctid(name)); if isempty(ny) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; %--------------------- %--- Grid Spacing. --- %--------------------- name = 'dxt'; dx = nctid{name}(1); if isempty(dx) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'dyt'; dy = nctid{name}(1); if isempty(dy) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; if (coord~=0) dx = dx.*cm2deg; dy = dy.*cm2deg; else dx = dx.*cm2m; dy = dy.*cm2m; end; %------------------------------ %--- Transformation Center. --- %------------------------------ name = 'rlngd'; lonc = nctid{name}(:); if isempty(lonc) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'rlatd'; latc = nctid{name}(:); if isempty(latc) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; %----------------------------------- %--- Transformation-Grid Offset. --- %----------------------------------- name = 'delx'; delx = nctid{name}(:); if (isempty(delx) & isempty(nctid{name}) & (coord==0)) delx = 0; elseif isempty(delx) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'dely'; dely = nctid{name}(:); if (isempty(dely) & isempty(nctid{name}) & (coord==0)) delx = 0; elseif isempty(dely) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; if (coord==0) delx = delx.*cm2m; dely = dely.*cm2m; end; %----------------- %--- Rotation. --- %----------------- name = 'thetad'; theta = nctid{name}(:); if isempty(theta) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; %------------------------ %--- Old PE versions. --- %------------------------ if (oldpe) deg2rad = pi/180; dx = dx*cos(latc*deg2rad) clear deg2rad end; clear oldpe %------------------------- %--- Group parameters. --- %------------------------- domdat = [coord nx ny dx dy lonc latc delx dely theta]; clear coord nx ny dx dy lonc latc delx dely theta; %------------------------------------------------------------------------------- % Read land masks. %------------------------------------------------------------------------------- name = 'landt'; landt = nctid{name}(:); if ~isempty(landt) tlndind = find (landt==0); elseif isempty(nctid{name}) tlndind = []; else disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'landv'; landv = ncvid{name}(:); if ~isempty(landv) vlndind = find (landv~=2); elseif isempty(ncvid{name}) vlndind = []; else disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),vfile,setstr(34)]); disp (' '); return; end; clear landt landv; %------------------------------------------------------------------------------- % Read time limitations. %------------------------------------------------------------------------------- timeoff = datenum(get_petim0(nctid)); if isempty(timeoff) disp (' '); disp ('***Error: GETPEDOM - unable to read initial time in netCDF file:'); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; name = 'time'; timend = nctid{name}(length(nctid(name))); if isempty(timend) disp (' '); disp (['***Error: GETPEDOM - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),tfile,setstr(34)]); disp (' '); return; end; timdat = [timeoff timend]; clear nctid ncvid tfile vfile timeoff timend name; return; %=============================================================================== function status = closhops (ncids,fnames); % % status = closhops (ncids,fnames); % % This function closes the HOPS PE netCDF files. % % ------ % Input: % ------ % % ncids....Cell array of netCDF identifiers to open files. % NCIDS{1} - netCDF identifer(s) for tracer file(s). % NCIDS{2} - netCDF identifer(s) for velocity file(s). % Can be same as tracer file. % fnames...Cell array of input file names. % FNAMES{1} - name(s) of tracer file(s). % FNAMES{2} - name(s) of velocity file(s). % Can be same as tracer file(s). % % ------- % Output: % ------- % % status...Exit status. Empty if successful, -1 if not. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- status = []; %------------------------------------------------------------------------------- % Loop over all nested domains, closing files. %------------------------------------------------------------------------------- ncidt = ncids{1}; tfile = fnames{1}; ncidv = ncids{2}; vfile = fnames{2}; for n = 1:length(tfile) stw = clos1hops ({ncidt{n} ncidv{n}},{tfile{n} vfile{n}}); status = [status stw]; end; clear ncidt ncidv tfile vfile n stw %------------------------------------------------------------------------------- % Set final exit status. %------------------------------------------------------------------------------- if ~isempty(status) status = -1; end; return; %=============================================================================== function status = clos1hops (ncids,fnames); % % status = clos1hops (ncids,fnames); % % This function closes the HOPS PE netCDF files. % % ------ % Input: % ------ % % ncids....Cell array of netCDF identifiers to open files. % NCIDS{1} - netCDF identifer for tracer file. % NCIDS{2} - netCDF identifer for velocity file. % Can be same as tracer file. % fnames...Cell array of input file names. % FNAMES{1} - name of tracer file. % FNAMES{2} - name of velocity file. % Can be same as tracer file. % % ------- % Output: % ------- % % status...Exit status. Empty if successful, -1 if not. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- status = []; st2 = []; %------------------------------------------------------------------------------- % Close files. %------------------------------------------------------------------------------- st1 = close(ncids{1}); if ~isempty(st1) disp (' '); disp ('***Error: CLOSHOPS - unable to close netCDF file:'); disp ([' ',setstr(34),fnames{1},setstr(34)]); disp (' '); end; if ~strcmp(fnames{1},fnames{2}) st2 = close(ncids{2}); if ~isempty(st2) disp (' '); disp ('***Error: CLOSHOPS - unable to close netCDF file:'); disp ([' ',setstr(34),fnames{2},setstr(34)]); disp (' '); end; end; %------------------------------------------------------------------------------- % Set final exit status. %------------------------------------------------------------------------------- if ~isempty([st1 st2]) status = -1; end; return; %=============================================================================== function [domt,xt,it,yt,jt,zt,tt,domv,xv,iv,yv,jv,zv,tv] = ... getpepos (lon,lat,depth,time,domdat,timdat); % % [domt,xt,it,yt,jt,zt,tt,domv,xv,iv,yv,jv,zv,tv] = ... % getpepos (lon,lat,depth,time,domdat,timdat); % % This function converts lon/lat/depth/time data into PE positions. %------------------------------------------------------------------------------- % Fix longitude branch. %------------------------------------------------------------------------------- deg2rad = pi/180; lon = atan2(sin(lon.*deg2rad),cos(lon.*deg2rad))./deg2rad; clear deg2rad; %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- domt = NaN.*lon; if (diff(size(domt))<0) domt = domt'; end; xt = domt; it = domt; yt = domt; jt = domt; zt = domt; tt = domt; domv = domt; xv = domt; iv = domt; yv = domt; jv = domt; zv = domt; tv = domt; %------------------------------------------------------------------------------- % Loop over all domains, or until all points converted. %------------------------------------------------------------------------------- [ndom,ncomp] = size(domdat); clear ncomp; %-------------------- %--- Tracer grid. --- %-------------------- n = 0; while ((n(domdat(2)-1)); if ~isempty(ind) it(ind) = domdat(2)-1; end; xt = xt - it; jt = floor(yt); ind = find (jt>(domdat(3)-2)); if ~isempty(ind) jt(ind) = domdat(3)-2; end; yt = yt - jt; %------------------------------------------------------------------------------- % Flag out-of-range locations. %------------------------------------------------------------------------------- ind = find ( (it<1) | (xt>1) | (jt<1) | (yt>1) | (tt<0) | (tt>timdat(2)) ); if ~isempty(ind) it(ind) = NaN; xt(ind) = NaN; jt(ind) = NaN; yt(ind) = NaN; zt(ind) = NaN; tt(ind) = NaN; end; return; %=============================================================================== function [xv,iv,yv,jv,zv,tv] = getpe1vpos (lon,lat,depth,time,domdat,timdat); % % [xv,iv,yv,jv,zv,tv] = getpe1vpos (lon,lat,depth,time,domdat,timdat); % % This function converts lon/lat/depth/time data into PE V-grid positions. %------------------------------------------------------------------------------- % Compute Velocity grid positions. %------------------------------------------------------------------------------- [xv,yv] = ll2xy (lon,lat,domdat); xv = xv - 0.5; yv = yv - 0.5; zv = - depth; tv = (datenum(time)' - timdat(1)).*86400; if (diff(size(xv))<0) xv = xv'; end; if (diff(size(yv))<0) yv = yv'; end; if (diff(size(zv))<0) zv = zv'; end; if any(size(tv)~=size(xv)) tv = tv'; end; %------------------------------------------------------------------------------- % Convert 2D positions to integral & fraction parts. %------------------------------------------------------------------------------- iv = floor(xv); ind = find (iv>(domdat(2)-2)); if ~isempty(ind) iv(ind) = domdat(2)-2; end; xv = xv - iv; jv = floor(yv); ind = find (jv>(domdat(3)-2)); if ~isempty(ind) jv(ind) = domdat(3)-2; end; yv = yv - jv; %------------------------------------------------------------------------------- % Flag out-of-range locations. %------------------------------------------------------------------------------- ind = find ( (iv<1) | (xv>1) | (jv<1) | (yv>1) | (tv<0) | (tv>timdat(2)) ); if ~isempty(ind) iv(ind) = NaN; xv(ind) = NaN; jv(ind) = NaN; yv(ind) = NaN; zv(ind) = NaN; tv(ind) = NaN; end; return; %=============================================================================== function vals = intrppe (varnam,ncid,fnam,vcind,dom,ipt,x,jpt,y,z,t,ny, ... lndind,xtrflg); % % vals = intrppe (varnam,ncid,fnam,vcind,dom,ipt,x,jpt,y,z,t,ny,lndind,xtrflg); % % This function interpolates the given field to the requested points. % % ------ % Input: % ------ % % varnam...Name of variable as it appears in netCDF file. % ncid.....Cell array of identifier(s) for opened netCDF file(s). % fnam.....Cell array of name of opened netCDF file(s). % vcind....Vector index to read. Set to empty ([]) for scalar variables. % dom......Domain to use for interpolating each point. % ipt......Integral part of X-positions at which to interpolate. % x........Fractional part of X-positions at which to interpolate. % jpt......Integral part of Y-positions at which to interpolate. % y........Fractional part of Y-positions at which to interpolate. % z........Depths at which to interpolate PE. (m) % t........Times at which to interpolate PE. (seconds since initialization) % ny.......Vector of number(s) of grid points in Y-direction. % lndind...Cell array of indices of lands points for each domain. % xtrflg...Flag for types of extrapolation allowed. % [0] no extrapolations. % [1] only extrapolate up (towards the surface). % [2] extrapolate in both directions. [default] % % ------- % Output: % ------- % % vals.....Interpolated values. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- vals = []; %------------------------------------------------------------------------------- % If no valid points, simply return NaN vector. %------------------------------------------------------------------------------- if ~any(~isnan(t(:))) vals = t; return; end; %------------------------------------------------------------------------------- % Loop over all unique domains, interpolating the fields. %------------------------------------------------------------------------------- valwk = NaN.*x; domU = unique(dom(find(~isnan(dom)))); for n = 1:length(domU); d = domU(n); ind = find (~isnan(dom) & (dom==d)); vald = intrppe1 (varnam,ncid{d},fnam{d},vcind,ipt(ind),x(ind),jpt(ind), ... y(ind),z(ind),t(ind),ny(d),lndind{d},xtrflg); if ~isempty(vald) valwk(ind) = vald; end; clear vald; end; vals = valwk; clear d domU n valwk; return; %=============================================================================== function vals = intrppe1 (varnam,ncid,fnam,vcind,ipt,x,jpt,y,z,t,ny,lndind, ... xtrflg); % % vals = intrppe1 (varnam,ncid,fnam,vcind,ipt,x,jpt,y,z,t,ny,lndind,xtrflg); % % This function interpolates the given field to the requested points. % % ------ % Input: % ------ % % varnam...Name of variable as it appears in netCDF file. % ncid.....Identifier for opened netCDF file. % fnam.....Name of opened netCDF file. % vcind....Vector index to read. Set to empty ([]) for scalar variables. % ipt......Integral part of X-positions at which to interpolate. % x........Fractional part of X-positions at which to interpolate. % jpt......Integral part of Y-positions at which to interpolate. % y........Fractional part of Y-positions at which to interpolate. % z........Depths at which to interpolate PE. (m) % t........Times at which to interpolate PE. (seconds since initialization) % ny.......Number of grid points in Y-direction. % lndind...Indices of lands points. % xtrflg...Flag for types of extrapolation allowed. % [0] no extrapolations. % [1] only extrapolate up (towards the surface). % [2] extrapolate in both directions. [default] % % ------- % Output: % ------- % % vals.....Interpolated values. %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- vals = []; %------------------------------------------------------------------------------- % Get secondary data. %------------------------------------------------------------------------------- %------------------ %--- PE depths. --- %------------------ znam = ncid{varnam}.positions(:); if isempty (znam) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34),varnam, ... ':positions',setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; %-------------------- %--- Fill values. --- %-------------------- vfill = ncid{varnam}.FillValue_(:); if isempty (vfill) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34),varnam, ... ':FillValue_',setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; %------------------ %--- PE times. --- %------------------ name = 'time'; tpe = ncid{name}(:); if isempty (tpe) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34),name, ... setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; %------------------------------------------------------------------------------- % Determine time indices. %------------------------------------------------------------------------------- nt = length(tpe); tindr = interp1 (tpe,(1:nt),t,'linear',NaN); wkind = find(~isnan(tindr)); tindlo = NaN.*tindr; twthi = tindlo; if ~isempty(wkind) tindlo(wkind) = floor(tindr(wkind)); ind = find(tindlo(wkind)>(nt-1)); if ~isempty(ind) tindlo(wkind(ind)) = nt-1; end; end; tindhi = tindlo + 1; if ~isempty(wkind) if any(size(t(wkind))~=size(tpe(tindlo(wkind)))) twk = t(wkind)'; else twk = t(wkind); end; twthi(wkind) = (twk-tpe(tindlo(wkind))) ... ./ (tpe(tindhi(wkind))-tpe(tindlo(wkind))); end; twtlo = 1 - twthi; clear tpe wkind; %------------------------------------------------------------------------------- % Loop over all unique times, interpolating the fields. %------------------------------------------------------------------------------- valwk = NaN.*x; tindloU = unique(tindlo(find(~isnan(tindlo)))); for n = 1:length(tindloU); tcurind = find((tindlo==tindloU(n)) & ~isnan(tindlo)); tilo = tindlo(tcurind(1)); tihi = tindhi(tcurind(1)); twlonow = twtlo(tcurind); twhinow = twthi(tcurind); xnow = x(tcurind); ynow = y(tcurind); znow = z(tcurind); inow = ipt(tcurind); jnow = jpt(tcurind); hind = jnow + (inow-1).*ny; hindU = unique(hind); valnow = NaN.*hind; %--------------------------------------------------------- %--- Loop over all unique 2x2 horizontal data squares. --- %--------------------------------------------------------- for m = 1:length(hindU) hereind = find(hind==hindU(m)); twlo = twlonow(hereind)'; twhi = twhinow(hereind)'; xhn = xnow(hereind); ihn = inow(hereind(1)); yhn = ynow(hereind); jhn = jnow(hereind(1)); zhn = znow(hereind); if any(size(twlo)~=size(xhn)) twlo = twlo'; end; if any(size(twhi)~=size(xhn)) twhi = twhi'; end; %----------------------- %--- Read PE depths. --- %----------------------- zpe = squeeze(ncid{znam}(jhn:(jhn+1),ihn:(ihn+1),:,3)); if isempty(zpe) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34), ... znam,setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; %----------------------- %--- Read PE values. --- %----------------------- if isempty(vcind) vpelo = squeeze(ncid{varnam}(tilo,jhn:(jhn+1),ihn:(ihn+1),:)); else vpelo = squeeze(ncid{varnam}(tilo,jhn:(jhn+1),ihn:(ihn+1),:,vcind)); end; if isempty(vpelo) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34), ... varnam,setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; ind = find (vpelo==vfill); if ~isempty(ind) vpelo(ind) = NaN; end; if isempty(vcind) vpehi = squeeze(ncid{varnam}(tihi,jhn:(jhn+1),ihn:(ihn+1),:)); else vpehi = squeeze(ncid{varnam}(tihi,jhn:(jhn+1),ihn:(ihn+1),:,vcind)); end; if isempty(vpehi) disp (' '); disp (['***Error: INTRPPE - unable to read ',setstr(34), ... varnam,setstr(34),' in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; ind = find (vpehi==vfill); if ~isempty(ind) vpehi(ind) = NaN; end; %----------------------------------------- %--- Extract free surface conversions. --- %----------------------------------------- [etalo,xfaclo] = get_fsurf (ncid,tilo,jhn,ihn,znam); if isempty(xfaclo) disp (' '); disp (['***Error: INTRPPE - unable to read free surface' ... ' parameters in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; [etahi,xfachi] = get_fsurf (ncid,tihi,jhn,ihn,znam); if isempty(xfachi) disp (' '); disp (['***Error: INTRPPE - unable to read free surface' ... ' parameters in netCDF file:']); disp ([' ',setstr(34),fnam,setstr(34)]); disp (' '); return; end; %----------------------------------------------- %--- Interpolate PE columns in the vertical. --- %----------------------------------------------- vlo = zeros(4,length(zhn)); vhi = vlo; for jj = 1:2 for ii = 1:2 ij = ii + (jj-1)*2; zwk = etalo(jj,ii) + xfaclo(jj,ii).*squeeze(zpe(jj,ii,:)); vi = interp1 (zwk,squeeze(vpelo(jj,ii,:)),zhn,'linear',NaN); ind = find(isnan(vi)); if (~isempty(ind) & (xtrflg~=0)) if (xtrflg==1) rmind = find ( abs(zhn(ind)) > max(abs(zwk(:))) ); if ~isempty(rmind) ind(rmind) = []; end; clear rmind; end; vix = interp1 (zwk,squeeze(vpelo(jj,ii,:)), ... zhn(ind),'nearest','extrap'); vi(ind) = vix; end; vlo(ij,:) = vi; zwk = etahi(jj,ii) + xfachi(jj,ii).*squeeze(zpe(jj,ii,:)); vi = interp1 (zwk,squeeze(vpehi(jj,ii,:)),zhn,'linear',NaN); ind = find(isnan(vi)); if (~isempty(ind) & (xtrflg~=0)) if (xtrflg==1) rmind = find ( abs(zhn(ind)) > max(abs(zwk(:))) ); if ~isempty(rmind) ind(rmind) = []; end; clear rmind; end; vix = interp1 (zwk,squeeze(vpehi(jj,ii,:)), ... zhn(ind),'nearest','extrap'); vi(ind) = vix; end; vhi(ij,:) = vi; end; end; %-------------------------------------- %--- Protect against masked values. --- %-------------------------------------- if ~isempty(lndind) goodpt = zeros(1,4); for dj = 0:1 for di = 0:1 indh = (jhn+dj) + (ihn+di-1).*ny; ind = di + 1 + dj*2; goodpt(ind) = isempty(find(lndind==indh)); end; end; gind = find(goodpt); bind = find(~goodpt); ngd = length(gind); indsum = sum(gind); if ((ngd>0) & (ngd<4)) avlo = mean(vlo(gind,:),1); avhi = mean(vhi(gind,:),1); if (ngd==3) avlo = 3.*avlo - 2.*vlo(indsum-5,:); avhi = 3.*avhi - 2.*vhi(indsum-5,:); end; if ((ngd~=2) | (indsum==5)); for k = 1:length(bind) vlo(bind(k),:) = avlo; vhi(bind(k),:) = avhi; end; else for k = 1:length(bind) vlo(bind(k),:) = vlo(indsum+bind(k)-5,:); vhi(bind(k),:) = vhi(indsum+bind(k)-5,:); end; end; elseif (ngd==0) vlo = vlo.*NaN; vhi = vhi.*NaN; end; end; %------------------------------------------------- %--- Interpolate PE columns in the horizontal. --- %------------------------------------------------- vhn = ((vlo(1,:).*(1-xhn)+vlo(2,:).*xhn).*(1-yhn) + ... (vlo(3,:).*(1-xhn)+vlo(4,:).*xhn).*yhn).*twlo + ... ((vhi(1,:).*(1-xhn)+vhi(2,:).*xhn).*(1-yhn) + ... (vhi(3,:).*(1-xhn)+vhi(4,:).*xhn).*yhn).*twhi; valnow(hereind) = squeeze(vhn); end; valwk(tcurind) = valnow; end; %------------------------------------------------------------------------------- % After fully successfully processing the fields, transfer the results % to the output variable. %------------------------------------------------------------------------------- vals = valwk; return; %=============================================================================== function [eta,xfac] = get_fsurf (ncid,tind,jind,iind,znam); % % [eta,xfac] = get_fsurf (ncid,tind,jind,iind,znam); % % This function extracts the conversions factors for depth under the free % surface. % % ------ % Input: % ------ % % ncid NetCDF identifier to open HOPS PE netCDF output file. % tind Time index to extract. % jind Starting j index to extract. % iind Starting i index to extract. % znam Name of depth variable % % ------- % Output: % ------- % % eta Free surface elevation. (m) % xfac Depth expansion factor. %------------------------------------------------------------------------------- % Quick by-pass for rigid-lid output. %------------------------------------------------------------------------------- if isempty(ncid{'srfpress'}) eta = zeros (2,2); xfac = ones (2,2); return; end; %------------------------------------------------------------------------------- % Initialize output. %------------------------------------------------------------------------------- eta = []; xfac = []; %------------------------------------------------------------------------------- % Get raw data. %------------------------------------------------------------------------------- if isempty(findstr('v',znam)) %--------------- %--- T-grid. --- %--------------- varnam = 'srfpress'; ps = squeeze(ncid{varnam}(tind,jind:(jind+1),iind:(iind+1))); if isempty(ps) disp (' '); disp (['***Error: GET_FSURF - unable to read ',setstr(34), ... varnam,setstr(34)]); disp (' '); return; end; varnam = 'tbath'; hbot = squeeze(ncid{varnam}(jind:(jind+1),iind:(iind+1))); if isempty(hbot) disp (' '); disp (['***Error: GET_FSURF - unable to read ',setstr(34), ... varnam,setstr(34)]); disp (' '); return; end; else %--------------- %--- V-grid. --- %--------------- varnam = 'srfpress'; pst = squeeze(ncid{varnam}(tind,jind:(jind+2),iind:(iind+2))); if isempty(pst) disp (' '); disp (['***Error: GET_FSURF - unable to read ',setstr(34), ... varnam,setstr(34)]); disp (' '); return; end; varnam = 'tbath'; hbott = squeeze(ncid{varnam}(jind:(jind+2),iind:(iind+2))); if isempty(hbott) disp (' '); disp (['***Error: GET_FSURF - unable to read ',setstr(34), ... varnam,setstr(34)]); disp (' '); return; end; n = 2:3; s = n - 1; e = n; w = s; ps = 0.25.*(pst(n,e) + pst(n,w) + pst(s,e) + pst(s,w)); hbot = 0.25.*(hbott(n,e) + hbott(n,w) + hbott(s,e) + hbott(s,w)); clear n s e w pst hbott; end clear varnam; %------------------------------------------------------------------------------- % Compute free surface and expansion factor. %------------------------------------------------------------------------------- cm2m = 0.01; grav = 980.6; p2h = cm2m./grav; eta = ps.*p2h; xfac = 1 + eta./abs(hbot); clear cm2m grav hbot p2h ps; return; %=============================================================================== function pe_tim0 = get_petim0 (ncid); % % pe_tim0 = get_petim0 (ncid); % % This function extracts the initial time from a HOPS PE output netCDF file. % % ------ % Input: % ------ % % ncid NetCDF identifier to open HOPS PE netCDF output file. % % ------- % Output: % ------- % % pe_tim0 HOPS PE starting time vector [year month day hour minute second]. %------------------------------------------------------------------------------- % Initialize output %------------------------------------------------------------------------------- pe_tim0 = []; %------------------------------------------------------------------------------- % Extract PE time units string %------------------------------------------------------------------------------- tim0str = ncid{'time'}.units(:); if isempty(tim0str) disp (' '); disp ('***Error: GET_PETIM0 - unable to read time units'); disp (' '); return; end; %------------------------------------------------------------------------------- % Remove all but initial time data %------------------------------------------------------------------------------- sind = findstr (upper(tim0str),'SINCE'); if isempty(sind) pe_tim0 = try_pejdate0 (ncid); return; end; if (length(tim0str)<=(sind+5)) pe_tim0 = try_pejdate0 (ncid); return; end; tim0str(1:(sind+4)) = []; clear sind; tim0str = fliplr(deblank(fliplr(deblank(tim0str)))); %------------------------------------------------------------------------------- % Convert to Gregorian data & GMT time %------------------------------------------------------------------------------- %-------------------------- %--- Remove Separators. --- %-------------------------- ind = findstr(tim0str,'-'); if ~isempty(ind) tim0str(ind(1:2)) = ' '; end; ind = findstr(tim0str,':'); if ~isempty(ind) tim0str(ind) = ' '; end; clear ind; %--------------------------- %--- Convert to Numeric. --- %--------------------------- twk = str2num (tim0str); clear tim0str %--------------------- %--- Shift to GMT. --- %--------------------- pe_tim0 = twk(1:6); gmtshft = twk(7:length(twk)); clear twk; repind = 2:length(gmtshft); gmtshft(repind) = abs(gmtshft(repind)).*sign(gmtshft(1)); repind = 3 + (1:length(gmtshft)); pe_tim0(repind) = pe_tim0(repind) + gmtshft; clear gmtshft repind; return; %=============================================================================== function pe_tim0 = try_pejdate0 (ncid); % % pe_tim0 = try_pejdate0 (ncid); % % This function tries extracts the initial time from a HOPS PE output netCDF % file, assuming the time is in modified Julian days. % % ------ % Input: % ------ % % ncid NetCDF identifier to open HOPS PE netCDF output file. % % ------- % Output: % ------- % % pe_tim0 HOPS PE starting time vector [year month day hour minute second]. %------------------------------------------------------------------------------- % Initialize output %------------------------------------------------------------------------------- pe_tim0 = []; %------------------------------------------------------------------------------- % Look for initial time variable in PE file. %------------------------------------------------------------------------------- pe_jdate0 = ncid{'time0'}(:); if isempty(pe_tim0) pe_jdate0 = ncid{'dstart'}(:); end; if isempty(pe_jdate0) disp (' '); disp ('***Error: TRY_PEJDATE0 - unable to extract starting time.'); disp (' '); return; end; %------------------------------------------------------------------------------- % Convert to Gregorian calendar. %------------------------------------------------------------------------------- pe_tim0 = gregorian (pe_jdate0+2440000); clear pe_jdate0; return; %=============================================================================== function [x,y] = ll2xy (lon,lat,coord,nx,ny,gridx,gridy,rlngd,rlatd, ... delx,dely,thetad) % %======================================================================= % === % function [x,y] = ll2xy (lon,lat,coord,nx,ny,gridx,gridy,rlngd, ... === % rlatd,delx,dely,thetad); === % === % This routine computes the grid coordinates from the given === % longitude and latitude. === % === % ------ === % Input: === % ------ === % === % LON, LAT the longitude and latitude of the point (deg) === % COORD flag for coordinate type === % [0] Cartesian (tangent plane) grid. === % [1] unrotated spherical grid. === % [2] rotated spherical grid. === % DELX, === % DELY, Offset between transform & grid centers. (m | deg) === % GRIDX grid spacing in x-direction (m | deg) === % GRIDY grid spacing in y-direction (m | deg) === % NX, NY number of grid points in x & y directions === % RLNGD longitude at center of transformation (deg) === % RLATD latitude at center of transformation (deg) === % THETAD angle grid is rotates with respect to east (deg) === % === % ------- === % Output: === % ------- === % === % X, Y the corresponding grid coordinates === % === %======================================================================= %======================================================================= % === % Calls: rotparm === % === %======================================================================= if (nargin==3) domdat = coord; coord = domdat(1); nx = domdat(2); ny = domdat(3); gridx = domdat(4); gridy = domdat(5); rlngd = domdat(6); rlatd = domdat(7); delx = domdat(8); dely = domdat(9); thetad = domdat(10); clear domdat; end; deg2rad = pi/180; xc = (nx+1)/2 - (delx/gridx); yc = (ny+1)/2 - (dely/gridy); %----------------------------------------------------------------------- % Cartesian (tangent plane) system. %----------------------------------------------------------------------- if (coord==0), re_d2r = 6371315.0*deg2rad; f1x = re_d2r/gridx; f1y = re_d2r/gridy; f2x = f1x*cos(rlatd*deg2rad); f2y = f1y*cos(rlatd*deg2rad); sterm = sin(thetad*deg2rad); cterm = cos(thetad*deg2rad); dlat = lat-rlatd; dlon = lon-rlngd; x = xc+f1x.*dlat.*sterm+f2x.*dlon.*cterm; y = yc+f1y.*dlat.*cterm-f2y.*dlon.*sterm; %----------------------------------------------------------------------- % Unrotated Spherical system. %----------------------------------------------------------------------- elseif (coord==1), x = xc+lon./gridx; y = yc+lat./gridy; %----------------------------------------------------------------------- % Rotated spherical system. %----------------------------------------------------------------------- else, rad2deg = 180/pi; [plon,plat,rnlon] = rotparm (rlngd*deg2rad,rlatd*deg2rad,thetad*deg2rad); cosp = cos(plat); sinp = sin(plat); cosl = cos(lat.*deg2rad); sinl = sin(lat.*deg2rad); rlat = asin(sinl.*sinp+cosl.*cosp.*cos(lon.*deg2rad-plon)); sin1 = cosl.*sin(lon.*deg2rad-plon); cos1 = sinl.*cosp-sinp.*cosl.*cos(lon.*deg2rad-plon); rlon = rnlon-atan2(sin1,cos1); ind = find(abs(rlon)>pi); if (~isempty(ind)), rlon(ind) = sign(rlon(ind)).*(rem(abs(rlon(ind)),2*pi) - ... 2.*pi.*fix(rem(abs(rlon(ind)),2*pi)./pi)); end; rlon = rlon.*rad2deg; rlat = rlat.*rad2deg; x = xc+rlon./gridx; y = yc+rlat./gridy; end; return; %=============================================================================== function [plon,plat,rnlon] = rotparm (clon,clat,rotang) % %======================================================================= % === % function [plon,plat,rnlon] = rotparm (clon,clat,rotang); === % === % This routine computes the parameters for a spherical rotation === % such that the new equator passes through the center point, === % making the prescribed angle with respect to East. === % === % On Input: === % === % CLON, CLAT The longitude and latitude of point center of the === % grid. (radians) === % ROTANG The angle of rotation with respect to East. === % (radians) === % === % On Output: === % === % PLON The longitude of the rotated pole in the original === % system. (radians) === % PLAT The latitude of the rotated pole in the original === % system. (radians) === % RNLON The longitude of the original pole in the rotated === % system. (radians) === % === %======================================================================= %======================================================================= % === % Calls: get_ewpt === % === %======================================================================= qpi = pi/4; %----------------------------------------------------------------------- % Compute the "eastern" and "western" points along the rotated equator. %----------------------------------------------------------------------- [elon,elat,wlon,wlat] = get_ewpt (clon,clat,rotang); %----------------------------------------------------------------------- % Compute the trigonometric functions of east and west latitudes and % of the difference of their longitudes. %----------------------------------------------------------------------- sine = sin(elat); sinw = sin(wlat); cose = cos(elat); cosw = cos(wlat); cosemw = cos(elon-wlon); sinemw = sin(elon-wlon); %----------------------------------------------------------------------- % Compute the trigonometric functions of the interior angles. %----------------------------------------------------------------------- sin_pen = sinw*cose - sine*cosw*cosemw; cos_pen = cosw*sinemw; sin_pwn = sine*cosw - sinw*cose*cosemw; cos_pwn = cose*sinemw; %----------------------------------------------------------------------- % Compute latitude of rotated pole. %----------------------------------------------------------------------- plat = asin( cose*cosw*sinemw ); %----------------------------------------------------------------------- % Compute longitude of rotated pole. Keep all longitudes in the % range (-pi, pi]. %----------------------------------------------------------------------- numer = sin_pen; denom = - cos_pen*sine; lon1 = elon + atan2(numer,denom); lon1=sign(lon1)*(rem(abs(lon1),2*pi) - 2*pi*fix(rem(abs(lon1),2*pi)/pi)); numer = sin_pwn; denom = - cos_pwn*sinw; lon2 = wlon - atan2(numer,denom); lon2=sign(lon2)*(rem(abs(lon2),2*pi) - 2*pi*fix(rem(abs(lon2),2*pi)/pi)); plon = ( lon1 + lon2 )/2; plon=sign(plon)*(rem(abs(plon),2*pi) - 2*pi*fix(rem(abs(plon),2*pi)/pi)); %----------------------------------------------------------------------- % Compute longitude of north pole in rotated coordinates. Keep all % longitudes in the range (-pi, pi]. %----------------------------------------------------------------------- numer = sin_pen*cose; denom = sine; lon1 = qpi - atan2(numer,denom); lon1=sign(lon1)*(rem(abs(lon1),2*pi) - 2*pi*fix(rem(abs(lon1),2*pi)/pi)); numer = sin_pwn*cosw; denom = sinw; lon2 = atan2(numer,denom) - qpi; lon2=sign(lon2)*(rem(abs(lon2),2*pi) - 2*pi*fix(rem(abs(lon2),2*pi)/pi)); rnlon = ( lon1 + lon2 )/2; rnlon=sign(rnlon)*(rem(abs(rnlon),2*pi)-2*pi*fix(rem(abs(rnlon),2*pi)/pi)); return; %=============================================================================== function [elon,elat,wlon,wlat] = get_ewpt (clon,clat,rotang) % %======================================================================= % === % function [elon,elat,wlon,wlat] = get_ewpt (clon,clat,rotang); === % === % This routine computes two points to determine a spherical === % rotation. In rotated system, the points would lie on the === % "equator" at "longitudes" 45E and 45W. === % === % On Input: === % === % CLAT, CLON The center of the grid. (radians) === % ROTANG The angle the new "equator" make with geographic === % east at the center of the grid. (radians) === % === % On Output: === % === % ELAT, ELON The geographic coordinates of the "east point". === % New latitude=0, New longitude=45. (radians) === % WLAT, WLON The geographic coordinates of the "west point". === % New latitude=0, New longitude=-45. (radians) === % === %======================================================================= %======================================================================= % === % Calls: none === % === %======================================================================= rrt2 = 1/sqrt(2); hpi = pi/2; %----------------------------------------------------------------------- % Find "eastern" point. %----------------------------------------------------------------------- colat = acos( rrt2*(sin(clat) + cos(clat)*sin(rotang)) ); elat = hpi - colat; if ( (colat~=0) & (colat~=pi) ), num = rrt2*(cos(clat) - sin(clat)*sin(rotang)); if (abs(rotang)<=pi/2), elon = clon + acos( num/sin(colat) ); else, elon = clon - acos( num/sin(colat) ); end; else elon = clon; end; %----------------------------------------------------------------------- % Find "western" point. %----------------------------------------------------------------------- colat = acos( rrt2*(sin(clat) - cos(clat)*sin(rotang)) ); wlat = hpi - colat; if ( (colat~=0) & (colat~=pi) ), num = rrt2*(cos(clat) + sin(clat)*sin(rotang)); if (abs(rotang)<=pi/2), wlon = clon - acos( num/sin(colat) ); else, wlon = clon + acos( num/sin(colat) ); end; else, wlon = clon; end; %----------------------------------------------------------------------- % Make sure latitudes are in the range [-pi/2, pi/2]. % Step 1: ensure that latitudes are in the range [-pi, pi]. % Step 2: further correct to [-pi/2, pi/2] (this involves % the longitudes). % Make sure longitudes are in the range [-pi, pi]. %----------------------------------------------------------------------- elat=sign(elat)*(rem(abs(elat),2*pi) - 2*pi*fix(rem(abs(elat),2*pi)/pi)); wlat=sign(wlat)*(rem(abs(wlat),2*pi) - 2*pi*fix(rem(abs(wlat),2*pi)/pi)); if (elat>pi/2), elat = pi - elat; elon = elon + pi; elseif (elat<-pi/2), elat = mpi - elat; elon = elon + pi; end; if (wlat>pi/2), wlat = pi - wlat; wlon = wlon + pi; elseif (wlat<-pi/2), wlat = mpi - wlat; wlon = wlon + pi; end; elon=sign(elon)*(rem(abs(elon),2*pi) - 2*pi*fix(rem(abs(elon),2*pi)/pi)); wlon=sign(wlon)*(rem(abs(wlon),2*pi) - 2*pi*fix(rem(abs(wlon),2*pi)/pi)); return; %=============================================================================== function [gtime]=gregorian(julian) %GREGORIAN Converts digital Julian days to Gregorian calendar dates. % Although formally, % Julian days start and end at noon, here Julian days % start and end at midnight for simplicity. % % In this convention, Julian day 2440000 begins at % 0000 hours, May 23, 1968. % % Usage: [gtime]=gregorian(julian) % % julian... input decimal Julian day number % % gtime is a six component Gregorian time vector % i.e. gtime=[yyyy mo da hr mi sec] % gtime=[1989 12 6 7 23 23.356] % yr........ year (e.g., 1979) % mo........ month (1-12) % d........ corresponding Gregorian day (1-31) % h........ decimal hours % % calls S2HMS julian=julian+5.e-9; % kludge to prevent roundoff error on seconds % if you want Julian Days to start at noon... % h=rem(julian,1)*24+12; % i=(h >= 24); % julian(i)=julian(i)+1; % h(i)=h(i)-24; secs=rem(julian,1)*24*3600; j = floor(julian) - 1721119; in = 4*j -1; y = floor(in/146097); j = in - 146097*y; in = floor(j/4); in = 4*in +3; j = floor(in/1461); d = floor(((in - 1461*j) +4)/4); in = 5*d -3; m = floor(in/153); d = floor(((in - 153*m) +5)/5); y = y*100 +j; mo=m-9; yr=y+1; i=(m<10); mo(i)=m(i)+3; yr(i)=y(i); [hour,min,sec]=s2hms(secs); gtime=[yr(:) mo(:) d(:) hour(:) min(:) sec(:)]; return; %=============================================================================== function [hour,min,sec]=s2hms(secs) %S2HMS converts seconds to integer hour,minute,seconds % sec=round(secs); hour=floor(sec/3600); min=floor(rem(sec,3600)/60); sec=round(rem(sec,60)); return