Home > fvcom_prepro > get_POLPRED_spectide.m

get_POLPRED_spectide

PURPOSE ^

Extract tidal harmonic phases and amplitudes from POLPRED ASCII files.

SYNOPSIS ^

function [Mobj] = get_POLPRED_spectide(Mobj, POLPRED)

DESCRIPTION ^

 Extract tidal harmonic phases and amplitudes from POLPRED ASCII files.

 get_POLPRED_spectide(Mobj, POLPRED)

 DESCRIPTION:
    Extract POLPRED harmonic amplitude and phases for the nearest point in
    the POLPRED grid to the open boundary nodes in Mobj.

 INPUT:
   Mobj    = MATLAB mesh object (see read_sms_mesh.m), with fields:
               - have_lonlat - flag indicating spherical coordinates
               - obc_nodes - open boundary node IDs
               - lon - longitude values
               - lat - latitude values
   POLPRED = ASCII file path of the POLPRED harmonics

 OUTPUT:
    Mobj  = MATLAB mesh object with two new arrays:
       phase - Harmonic phases at each open boundary point
       amp   - Harmonic amplitudes at each open boundary point

 EXAMPLE USAGE
    Mobj = get_POLPRED_spectide(Mobj, '/path/to/POLPRED.txt')

 Author(s):  
    Pierre Cazenave (Plymouth Marine Laboratory)

 Revision history
    2012-11-15 First version. Based in part on tide_tools.py from the
    PyFVCOM Python toolbox (https://gitlab.em.pml.ac.uk/pica/PyFVCOM)
    and Ricardo Torres' searchtides.m.

==========================================================================

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [Mobj] = get_POLPRED_spectide(Mobj, POLPRED)
0002 % Extract tidal harmonic phases and amplitudes from POLPRED ASCII files.
0003 %
0004 % get_POLPRED_spectide(Mobj, POLPRED)
0005 %
0006 % DESCRIPTION:
0007 %    Extract POLPRED harmonic amplitude and phases for the nearest point in
0008 %    the POLPRED grid to the open boundary nodes in Mobj.
0009 %
0010 % INPUT:
0011 %   Mobj    = MATLAB mesh object (see read_sms_mesh.m), with fields:
0012 %               - have_lonlat - flag indicating spherical coordinates
0013 %               - obc_nodes - open boundary node IDs
0014 %               - lon - longitude values
0015 %               - lat - latitude values
0016 %   POLPRED = ASCII file path of the POLPRED harmonics
0017 %
0018 % OUTPUT:
0019 %    Mobj  = MATLAB mesh object with two new arrays:
0020 %       phase - Harmonic phases at each open boundary point
0021 %       amp   - Harmonic amplitudes at each open boundary point
0022 %
0023 % EXAMPLE USAGE
0024 %    Mobj = get_POLPRED_spectide(Mobj, '/path/to/POLPRED.txt')
0025 %
0026 % Author(s):
0027 %    Pierre Cazenave (Plymouth Marine Laboratory)
0028 %
0029 % Revision history
0030 %    2012-11-15 First version. Based in part on tide_tools.py from the
0031 %    PyFVCOM Python toolbox (https://gitlab.em.pml.ac.uk/pica/PyFVCOM)
0032 %    and Ricardo Torres' searchtides.m.
0033 %
0034 %==========================================================================
0035 
0036 subname = 'get_POLPRED_spectide';
0037 
0038 global ftbverbose;
0039 if ftbverbose
0040   fprintf('\n')
0041   fprintf(['begin : ' subname '\n'])
0042 end
0043 
0044 % Check we have spherical coordinates in Mobj (we can't extract harmonics
0045 % without them (easily)).
0046 if ~Mobj.have_lonlat
0047     error('Spherical coordinates absent from Mobj. Cannot extract harmonics from cartesian coordinates.')
0048 end
0049 
0050 % Read the POLPRED header into a struct of header names plus their values.
0051 fid = fopen(POLPRED,'rt');
0052 if(fid < 0)
0053     error(['file: ' POLPRED ' does not exist']);
0054 end
0055 
0056 if ftbverbose
0057   fprintf(['reading from: ' POLPRED '\n'])
0058   fprintf('extracting header\n')
0059 end
0060 
0061 readingHeader = true;
0062 header = struct();
0063 while readingHeader
0064     lin = fgetl(fid);
0065     if isempty(lin)
0066         % Got to the end of the header
0067         readingHeader = false;
0068     else
0069         % We have some header information. Load it into a struct.
0070         key = regexp(lin, ':', 'split');
0071         header.(strtrim(regexprep(key{1}, ' ', '_'))) = strtrim(key{2});
0072     end
0073 end
0074 
0075 % Reformat the list of harmonics into a more sensible format
0076 header.Harmonics = regexp(header.Harmonics, ' ', 'split');
0077 
0078 % Get the positions in header.Harmonics for the constituents in which we're
0079 % interested.
0080 
0081 pInd = 1:length(header.Harmonics);
0082 pIndUse = nan(length(Mobj.Components), 2);
0083 for i=1:length(Mobj.Components)
0084     pPos = pInd(strcmp(Mobj.Components{i}, header.Harmonics));
0085     if isempty(pPos)
0086         warning('Supplied constituent (%s) is not present in the POLPRED data', Mobj.Components{i}) %#ok<WNTAG>
0087     else
0088         % Make index start at zero so the multiplication works, but
0089         % compensate for that once the offset has been applied. Also add
0090         % offset for the 2 columns (amplitude and phase).
0091         pIndUse(i, :) = (repmat((pPos - 1 ) * 6, 1, 2) + 1) + (0:1);
0092     end
0093 end
0094 % Add three to offset by the lat, lon and flag columns
0095 pIndUse = pIndUse + 3;
0096 
0097 % Now we're at the data. Load it all into a massive array.
0098 if ftbverbose
0099   fprintf('extracting data\n')
0100 end
0101 
0102 readingData = true;
0103 i = 0;
0104 % Preallocate data to something big and then cut back afterwards (if
0105 % necessary). Get the number of columns from the header and multiply by 6
0106 % (amplitude and phases for z, u and v). Add three for the lat, lon and
0107 % flag columns). The rows is the number of data lines in my files for the
0108 % northwest European shelf domain.
0109 nCols = 3 + (str2double(header.Number_of_harmonics) * 6);
0110 data = nan(358797, nCols);
0111 if ftbverbose
0112     tic
0113 end
0114 while readingData
0115     lin = fgetl(fid);
0116     if lin ~= -1 % EOF is -1
0117         i = i + 1;
0118         if ftbverbose
0119             if mod(i, 10000) == 0
0120                 fprintf('line %i\n', i)
0121             end
0122         end
0123         % str2double doesn't work without a couple of calls to regexp,
0124         % which makes it ~20x slower than str2num on its own. The regexp
0125         % approach is still here if you don't believe me.
0126         data(i, :) = str2num(strtrim(lin)); %#ok<ST2NM>
0127 %         data(i, :) = str2double(regexp(regexprep(strtrim(lin), '\s+', ' '), ' ', 'split'));
0128     else
0129         if ftbverbose
0130             fprintf('end of file at line %i\n', i)
0131         end
0132         readingData = false;
0133     end
0134 end
0135 if ftbverbose
0136     toc
0137 end
0138 
0139 fclose(fid);
0140 
0141 % Clear out any additional NaNs in data from preallocation.
0142 data = reshape(data(~isnan(data)), i, nCols);
0143 
0144 % Now we have the data, identify the indices of data which correspond to
0145 % the nearest point to each open boundary point. This approach may not be
0146 % the best: it might instead be better to simply read in the positions and
0147 % create an index which we use to extract the harmonics of interest.
0148 % However, we've got this far so might as well carry on.
0149 
0150 % Get the open boundary node IDs with which to extract their locations
0151 tmpObcNodes = Mobj.obc_nodes';
0152 ObcNodes = tmpObcNodes(tmpObcNodes~=0)';
0153 obc_lon = Mobj.lon(ObcNodes);
0154 obc_lat = Mobj.lat(ObcNodes);
0155 
0156 % For each position, find the nearest POLPRED value. Use the
0157 % find_nearest_pt.m logic to get the nearest point (we can't use the
0158 % function here because the values for which we're searching aren't in
0159 % Mobj).
0160 distance = nan(size(obc_lon));
0161 point = nan(size(distance));
0162 % Omit the NaNs in the indices from POLPRED when calculating the output
0163 % array size.
0164 amp = nan(length(obc_lon), length(pIndUse(~isnan(pIndUse(:, 1)), 1)));
0165 phase = nan(size(amp));
0166 for i=1:length(obc_lon)
0167     radvec = sqrt((obc_lon(i)-data(:,2)).^2 + (obc_lat(i)-data(:,1)).^2);
0168     [distance(i), point(i)] = min(radvec);
0169     % Get the amplitude and phase for each constituent (in order of
0170     % Mobj.Components). Check for and omit NaNs here (for missing tidal
0171     % constituents in the supplied list and what's given in POLPRED).
0172     amp(i, :) = data(point(i), pIndUse(~isnan(pIndUse(:, 1)), 1));
0173     phase(i, :) = data(point(i), pIndUse(~isnan(pIndUse(:, 1)), 2));
0174 end
0175 
0176 % Check for and warn about NaNs (-999.9 in POLPRED data).
0177 if sum(amp(:)==-999.9) > 0
0178     warning('NaN values (-999.9 in POLPRED terms) in the amplitude data. Are your boundaries on land?') %#ok<WNTAG>
0179 end
0180 if sum(phase(:)==-999.9) > 0
0181     warning('NaN values (-999.9 in POLPRED terms) in the phase data. Are your boundaries on land?') %#ok<WNTAG>
0182 end
0183 
0184 Mobj.amp = amp;
0185 Mobj.phase = phase;
0186 
0187 % Plot the open boundary positions and the closest POLPRED point.
0188 % figure(1000)
0189 % plot(obc_lon, obc_lat, 'o')
0190 % hold on
0191 % plot(data(point,2), data(point,1), 'rx')
0192

Generated on Wed 20-Feb-2019 16:06:01 by m2html © 2005