function MRI_struct = computeMRIpeaks( bldg_struct, DIF_struct_cell, HURR_struct, MRI_list ) % check to make sure that bldg_struct and DIF_struct correspond % if the terrain conditions are directional, then DIF_struct should be % a structure array of length 2, with one "open" and one "suburban" % DIF_struct should be consistent % PROCEDURE: % for each building orientation: % define list of wind directions relative to reference axis % compute DIFs for each wind direction err_dlgname = 'Error computing MRI peaks'; tol = 10^-3; % Convert the input 'DIF_struct_cell' to a structure array 'DIF_struct' in which each element has the same fields: if length(DIF_struct_cell)==1 DIF_struct = DIF_struct_cell{1}; n_r = length(DIF_struct(1).resp_names); % number of responses % make sure terrain in DIF results matches building input file: if ~ismember(bldg_struct.terrain, {DIF_struct.terrain,'Directional'}) err = errordlg(['The terrain in the building input file (''' bldg_struct.terrain ... ''') does not match the terrain in the DIF results file (''' DIF_struct.terrain ''').'],err_dlgname); uiwait(err); MRI_struct.error = 1; return; end elseif length(DIF_struct_cell)==2 % Make sure building input file specifies 'Directional' terrain: if ~strcmp(bldg_struct.terrain,'Directional') err = errordlg(['Only one DIF results file expected for the terrain specified in the building input file (''' bldg_struct.terrain ... '''). Multiple DIF results allowed for ''Directional'' terrain only.' ],err_dlgname); uiwait(err); MRI_struct.error = 1; return; end fields1 = fieldnames(DIF_struct_cell{1}); fields2 = fieldnames(DIF_struct_cell{2}); fields = intersect(fields1,fields2); % Create a structure array containing only the common fields: for i=1:2 for j=1:length(fields) DIF_struct(i).(fields{j}) = DIF_struct_cell{i}.(fields{j}); end end % Make sure the terrain does not coincide for the two DIF results (one should be 'Open_Country' and one should be 'Suburban'): if strcmp(DIF_struct(1).terrain, DIF_struct(2).terrain) err = errordlg(['Both DIF files correspond to the same type of terrain (''' DIF_struct(1).terrain ... '''). DIF files for both ''Open_Country'' and ''Suburban'' terrain are required to compute MRIs by interpolation.'],err_dlgname); uiwait(err); MRI_struct.error = 1; return; % make sure units, wind directions, frame locations, and building dimensions coincide: elseif ~strcmp(DIF_struct(1).force_units,DIF_struct(2).force_units) err = errordlg('The force units must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif ~strcmp(DIF_struct(1).length_units,DIF_struct(2).length_units) err = errordlg('The length units must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif ~strcmp(DIF_struct(1).ws_units,DIF_struct(2).ws_units) err = errordlg('The wind speed units must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif length(DIF_struct(1).theta)~=length(DIF_struct(i).theta) || any(DIF_struct(1).theta~=DIF_struct(i).theta) err = errordlg( 'The wind directions must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif any(size(DIF_struct(1).frame_coords)~=size(DIF_struct(2).frame_coords)) || max(max(abs(DIF_struct(1).frame_coords-DIF_struct(2).frame_coords)))>tol err = errordlg( 'The frame coordinates must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif max(max(abs(DIF_struct(1).d0-DIF_struct(2).d0)))>tol err = errordlg( 'The building dimensions must coincide for all DIF results used in interpolation',err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif size(DIF_struct(1).d,1)~=size(DIF_struct(2).d,1) || any(any(DIF_struct(1).d~=DIF_struct(2).d)) err = errordlg( 'The model dimensions must coincide for all DIF results used in interpolation.',err_dlgname); uiwait(err); MRI_struct.error = 1; return; end % make sure the number of responses, the response names, and the response units coincide: if length(DIF_struct(1).resp_names)~=length(DIF_struct(2).resp_names) err = errordlg('The number of response quantities must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; end n_r = length(DIF_struct(1).resp_names); for j=1:n_r if ~strcmp(DIF_struct(1).resp_names(j), DIF_struct(2).resp_names(j)) err = errordlg('The response names must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; elseif ~strcmp(DIF_struct(1).resp_units(j), DIF_struct(2).resp_units(j)) err = errordlg('The response units must coincide for all DIF results used in interpolation', err_dlgname); uiwait(err); MRI_struct.error = 1; return; end end else err = errordlg(['Unexpected number of DIF files (' num2str(length(DIF_struct_cell)) '; 1 or 2 expected.'], err_dlgname); uiwait(err); MRI_struct.error = 1; return; end MRI_struct.length_units = bldg_struct.length_units; MRI_struct.force_units = bldg_struct.force_units; MRI_struct.ws_units = bldg_struct.ws_units; MRI_struct.d0 = bldg_struct.d0; MRI_struct.d = DIF_struct(1).d; MRI_struct.frame_coords = bldg_struct.frame_coords; MRI_struct.terrain = bldg_struct.terrain; MRI_struct.z0 = bldg_struct.z0; MRI_struct.model_terrain = {DIF_struct.terrain}; MRI_struct.resp_names = DIF_struct(1).resp_names; MRI_struct.resp_units = DIF_struct(1).resp_units; % Identify which quantities are available to interpolate: % initialize boolean values for which quantities to interpolate: max_obs = 1; min_obs = 1; max_est = 1; min_est = 1; for i = 1:length(DIF_struct) if ~isfield(DIF_struct, 'X_max_obs') || isempty(DIF_struct(i).X_max_obs) max_obs = 0; elseif max_obs==1 X_max_obs = DIF_struct(i).X_max_obs; n_f = size(X_max_obs,3); % 'wrap' DIFs above 360 and below 0 to facilitate resampling: DIF(i).X_max_obs_wrap = cat(2,X_max_obs,X_max_obs,X_max_obs); end if ~isfield(DIF_struct, 'X_min_obs') || isempty(DIF_struct(i).X_min_obs) min_obs = 0; elseif min_obs==1 X_min_obs = DIF_struct(i).X_min_obs; n_f = size(X_min_obs,3); % 'wrap' DIFs above 360 and below 0 to facilitate resampling: DIF(i).X_min_obs_wrap = cat(2,X_min_obs,X_min_obs,X_min_obs); end if ~isfield(DIF_struct, 'X_max_est') || isempty(DIF_struct(i).X_max_est) max_est = 0; elseif max_est==1 X_max_est = DIF_struct(i).X_max_est; n_f = size(X_max_est,3); % 'wrap' DIFs above 360 and below 0 to facilitate resampling: DIF(i).X_max_est_wrap = cat(2,X_max_est,X_max_est,X_max_est); end if ~isfield(DIF_struct, 'X_min_est') || isempty(DIF_struct(i).X_min_est) min_est = 0; elseif min_est==1 X_min_est = DIF_struct(i).X_min_est; n_f = size(X_min_est,3); % 'wrap' DIFs above 360 and below 0 to facilitate resampling: DIF(i).X_min_est_wrap = cat(2,X_min_est,X_min_est,X_min_est); end end if ~max_obs & ~min_obs & ~max_est & ~min_est err = errordlg('Neither observed nor estimated DIF results are available for interpolation',err_dlgname); uiwait(err); MRI_struct.error = 1; return; end MRI_struct.max_obs = max_obs; MRI_struct.min_obs = min_obs; MRI_struct.max_est = max_est; MRI_struct.min_est = min_est; MRI_struct.DIF_struct = DIF_struct; theta = DIF_struct(1).theta; if any(theta~=sort(theta)) error('DIF_struct.theta must be sorted in increasing order'); end % 'wrap' wind directions above 360 and below 0 to facilitate resampling: theta_wrap = [theta(:)-360; theta(:); theta(:)+360]; % define upper and lower boundaries of sector for each wind direction: theta_wrap_max = theta_wrap; theta_wrap_max(1:end-1) = theta_wrap(1:end-1)+ 0.5*diff(theta_wrap); theta_wrap_min = theta_wrap; theta_wrap_min(2:end) = theta_wrap(2:end) - 0.5*diff(theta_wrap); % define list of orientations of ridge axis of building: d_a0 = 15; % increment in orientation (degrees) alpha_0 = 0:d_a0:360-d_a0; % orientations (degrees clockwise from north) n_o = length(alpha_0); % number of orientations considered % Scale directional wind speeds to eave height over appropriate terrain: Vsim = HURR_struct.Vsim; % matrix of simulated wind speeds (1-hour average in mph at 10 m elevation over open terrain) % define list of wind directions corresponding to the columns of HURR_struct.Vsim: if size(Vsim,2)==16 alpha = 22.5:22.5:360; % (degrees clockwise from north) delta_alpha = 22.5; % increment in wind direction n_q = length(alpha); % number of wind directions else err = errordlg(['Unexpected number of columns in HURR_struct.Vsim (' num2str(size(Vsim,2)) '); 16 expected.'], err_dlgname); uiwait(err); MRI_struct.error = 1; return; end Z = 10; % elevation (m) corresponding to wind speeds in Vsim Z0 = 0.03; % roughness length (m) corresponding to wind speeds in Vsim H = bldg_struct.d0(3); % eave height (units should be 'ft') if strcmp(bldg_struct.length_units,'ft') H = H*.3048; % convert eave height from 'ft' to 'm' else err = errordlg('Length units in building input file must be ''ft''', err_dlgname); uiwait(err); MRI_struct.error = 1; return; end if strcmp(bldg_struct.terrain, 'Open_Country') z0 = 0.03*ones(size(alpha)); %roughness lengths (m) DIF.mu = ones(size(alpha)); elseif strcmp(bldg_struct.terrain, 'Suburban') z0 = 0.3*ones(size(alpha)); % roughness lengths (m) DIF.mu = ones(size(alpha)); elseif strcmp(bldg_struct.terrain, 'Directional') z0 = interp1(0:45:360, [bldg_struct.z0 bldg_struct.z0(1)], alpha)*.3048; % roughness lengths (m) if length(DIF_struct)==1 % DIFs from either 'Open_Country' or 'Suburban' terrain will be used to compute MRIs (no interpolation) DIF.mu = ones(size(alpha)); elseif length(DIF_struct)==2 % Interpolation between DIFs for 'Open_Country' and 'Suburban' terrain for i=1:length(DIF_struct) % Define weighting factors for interpolation between 'Open_Country' and 'Suburban' DIFs: if strcmp(DIF_struct(i).terrain, 'Open_Country') DIF(i).mu = (.3-z0)/(0.3-0.03); DIF(i).mu(find(z0>0.3)) = 0; DIF(i).mu(find(z0<0.03)) = 1; elseif strcmp(DIF_struct(i).terrain, 'Suburban') DIF(i).mu = (z0-0.03)/(0.3-0.03); DIF(i).mu(find(z0>0.3)) = 1; DIF(i).mu(find(z0<0.03)) = 0; else err = errordlg(['The terrain specified in the DIF file (''' DIF_struct(i).terrain ... ''') is unrecognized; either ''Open_Country'' or ''Suburban'' expected.'],err_dlgname); uiwait(err); MRI_struct.error = 1; return; end end end else err = errordlg(['The terrain specified in the building input file (''' bldg_struct(i).terrain ... ''') is unrecognized; either ''Open_Country'', ''Suburban'', or ''Directional'' expected.'],err_dlgname); uiwait(err); MRI_struct.error = 1; return; end lambda = (z0/Z0).^0.0706.*log(H./z0)/log(Z/Z0); % scale factors for each direction V_H = Vsim*diag(lambda); % wind speeds scaled to eave height over appropriate terrain h = size(V_H,1); % number of hurricanes mu = HURR_struct.recurrence; % hurricane recurrence rate MRI_rank = (1-exp(-mu*(1:h)/(h+1))).^-1; % MRIs associated with ranked responses MRI_struct.milepost = HURR_struct.milepost; if ~exist('MRI_list') || isempty(MRI_list) % Prompt user to select MRIs for which responses are desired: MRI_list = [50 100 250 500 750 1000]; MRI_list = MRI_list(find(MRI_list=0 theta_hat(find(theta_hat>=360)) = theta_hat(find(theta_hat>=360))-360; % make sure theta_hat is <360 DIF_hat(o).theta_hat = theta_hat; % define upper and lower boundaries of sector for each wind direction: theta_hat_max = theta_hat+delta_alpha/2; theta_hat_min = theta_hat-delta_alpha/2; % RESAMPLE DIFs: % initialize empty arrays: if max_obs DIF_hat(o).X_max_obs = zeros(n_r,n_q,n_f); end if min_obs DIF_hat(o).X_min_obs = zeros(n_r,n_q,n_f); end if max_est DIF_hat(o).X_max_est = zeros(n_r,n_q,n_f); end if min_est DIF_hat(o).X_min_est = zeros(n_r,n_q,n_f); end for q=1:length(theta_hat) % loop through wind directions overlap = min(theta_wrap_max, theta_hat_max(q)*ones(size(theta_wrap_max)))... - max(theta_wrap_min, theta_hat_min(q)*ones(size(theta_wrap_min))); overlap(find(overlap<0))=0; overlap_fraction = overlap/delta_alpha; for f=1:n_f % loop through frames for i=1:length(DIF_struct) if max_obs DIF_hat(o).X_max_obs(:,q,f) = DIF_hat(o).X_max_obs(:,q,f)... + DIF(i).mu(q)*sum(DIF(i).X_max_obs_wrap(:,:,f)*diag(overlap_fraction),2); end if min_obs DIF_hat(o).X_min_obs(:,q,f) = DIF_hat(o).X_min_obs(:,q,f)... + DIF(i).mu(q)*sum(DIF(i).X_min_obs_wrap(:,:,f)*diag(overlap_fraction),2); end if max_est DIF_hat(o).X_max_est(:,q,f) = DIF_hat(o).X_max_est(:,q,f)... + DIF(i).mu(q)*sum(DIF(i).X_max_est_wrap(:,:,f)*diag(overlap_fraction),2); end if min_est DIF_hat(o).X_min_est(:,q,f) = DIF_hat(o).X_min_est(:,q,f)... + DIF(i).mu(q)*sum(DIF(i).X_min_est_wrap(:,:,f)*diag(overlap_fraction),2); end end end end for f=1:n_f % loop through frames for r=1:n_r % loop through responses if max_obs r_rank = sort(max(V_H.^2*diag(DIF_hat(o).X_max_obs(r,:,f)),[],2),1,'descend'); % rank ordered max responses in each hurricane MRI_struct.MRI_max_obs(:,f,o,r) = interp1(MRI_rank, r_rank, MRI_list ,'cubic'); end if min_obs r_rank = sort(min(V_H.^2*diag(DIF_hat(o).X_min_obs(r,:,f)),[],2),1,'ascend'); % rank ordered min responses in each hurricane MRI_struct.MRI_min_obs(:,f,o,r) = interp1(MRI_rank, r_rank, MRI_list ,'cubic'); end if max_est r_rank = sort(max(V_H.^2*diag(DIF_hat(o).X_max_est(r,:,f)),[],2),1,'descend'); % rank ordered max responses in each hurricane MRI_struct.MRI_max_est(:,f,o,r) = interp1(MRI_rank, r_rank, MRI_list ,'cubic'); end if min_est r_rank = sort(min(V_H.^2*diag(DIF_hat(o).X_min_est(r,:,f)),[],2),1,'ascend'); % rank ordered min responses in each hurricane MRI_struct.MRI_min_est(:,f,o,r) = interp1(MRI_rank, r_rank, MRI_list ,'cubic'); end end end end MRI_struct.DIF_hat = DIF_hat; % Unknown orientation -- expected peaks for uniform probability of each orientation: if max_obs MRI_struct.MRI_UKO_max_obs = squeeze(mean(MRI_struct.MRI_max_obs,3)); end if min_obs MRI_struct.MRI_UKO_min_obs = squeeze(mean(MRI_struct.MRI_min_obs,3)); end if max_est MRI_struct.MRI_UKO_max_est = squeeze(mean(MRI_struct.MRI_max_est,3)); end if min_est MRI_struct.MRI_UKO_min_est = squeeze(mean(MRI_struct.MRI_min_est,3)); end