├── LICENSE ├── MuLTI.m ├── MuLTI_III.m ├── Publications ├── Killingbeck_et_al-2018-Geochemistry,_Geophysics,_Geosystems.pdf ├── Killingbeck_et_al-2019-Annals of Glaciology.pdf └── Killingbeck_et_al-2020_GRL.pdf ├── README.md ├── examples ├── Example input data for MuLTI_III │ ├── dendata.mat │ ├── input_data.mat │ ├── true_Vs_model.mat │ └── vpdata.mat ├── Input data for examples 1-4 │ ├── 1.2.Synthetic_DWN_picks_long_offset.mat │ ├── 3.Synthetic_DWN_picks_48geophones.mat │ ├── 4.real_data_picks.mat │ └── true_model_vs.mat ├── MuLTI_examples1-4_scripts │ ├── MuLTI_1_Constrained_DWN_1_100Hz.m │ ├── MuLTI_1_Constrained_DWN_1_140Hz.m │ ├── MuLTI_2_Constrained_DWN_14_100Hz.m │ ├── MuLTI_2_NONConstrained_DWN_14_100Hz.m │ ├── MuLTI_3_Constrained_DWN_48geophones.m │ └── MuLTI_4_Constrained_real_data.m └── Output data from examples 1-4 │ ├── 1.Constrained_DWN_1_100Hz.mat │ ├── 1.Constrained_DWN_1_140Hz.mat │ ├── 2.Constrained_DWN_14_100Hz.mat │ ├── 2.NONConstrained_DWN_14_100Hz.mat │ ├── 3.Constrained_DWN_48_geophones.mat │ └── 4.Constrained_Real_data.mat ├── functions ├── thicknesses_and_priors.m ├── thicknesses_and_priors_III.m └── whichnuclei.m ├── gpdc mex file LINUX ├── READ_ME.txt ├── gpdc.cpp └── gpdc_test.m ├── gpdc mex file WINDOWS ├── QGpCoreTools1.dll ├── QGpCoreWave1.dll ├── QtCore4.dll ├── READ_ME.txt ├── gpdc.cpp ├── gpdc.mexw64 ├── gpdc_test.m ├── libgcc_s_seh-1.dll ├── libstdc++-6.dll └── libwinpthread-1.dll └── tools ├── Plotting_1D_PDFs.m ├── cmap.mat ├── cmap_b.mat └── plotting_MuLTI_III_PDFs.m /MuLTI.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % MuLTI % 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % This Matlab script runs a transdimensional MCMC 5 | % inversion for S-Wave data 6 | 7 | % Author: Phil Livermore / Siobhan Killingbeck 8 | % School of Earth and Environemnt, The University of Leeds 9 | % It is based on Matlab code written by Thomas Bodin. 10 | 11 | % The physical model consists of internal layers, each with an associated shear wave 12 | % speed vs defined by Voronoi nuclei. 13 | 14 | % The domain is divided into a number of layers, num_layers (which could be one) 15 | % each with its own prior distribution on Vs. 16 | 17 | % Each layer has a special nuclei that cannot leave its layer ("confined" nuclei). 18 | % npt is the number of "floating" nuclei that can change layer. 19 | 20 | % The total number of nuclei is therefore npt_max + num_layers 21 | 22 | clear all % clear all the variables previously allocated 23 | close all % close all the figures 24 | 25 | %%%%%%%%%%%%%%%%%%%%%%%%%LOAD DATA%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 26 | %%%%%%%%%Loading dispersion curves picked from 1D shot gathers%%%%%%%%%%%%% 27 | 28 | load('input_data.mat'); %load picked dispersion curves 29 | freq = data(:,1);% set frequency 30 | data = data(:,2); % set observed data 31 | nd =numel(data); % nd is the number of data points 32 | 33 | %determine fitting error of picking dispersion curve in m/s 34 | fitting_error = half_width(:,2); % set fitting error to half width of waveform's dispersion image 35 | 36 | running_mode = 1; %1 -> find posterior; 0 -> Find priors. 37 | 38 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 39 | % VERY IMPORTANT PARAMETERS 40 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%th 41 | 42 | burn_in=10000; % burn-in period 43 | nsample=1000000; % total number of samples 44 | 45 | %Uniform prior on depths for nuclei 46 | priors.depth_min=0; % Cannot be changed, always from the surface. 47 | priors.depth_max=40; 48 | priors.npt_max = 30; 49 | priors.npt_min = 0; 50 | 51 | num_layers = 3; % depth constraining parameter, if set to 1 no depth constraints will be applied. 52 | 53 | priors.layer_depths = zeros(num_layers-1,1); %the last layer depth is infinity (and is not defined). 54 | priors.vsmin = zeros(num_layers,1); 55 | priors.vsmax = zeros(num_layers,1); 56 | priors.vp = zeros(num_layers,1); 57 | priors.density = zeros(num_layers,1); 58 | 59 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 60 | % Define the priors and layer geometry 61 | if num_layers == 3 62 | priors.layer_depths(1) = 2 ; % layer 1 depth. 63 | priors.layer_depths(2) = 25.5 ; % layer 2 depth. 64 | priors.vsmin(1) = 500; % layer 1 65 | priors.vsmax(1) = 1700; 66 | priors.vsmin(2) = 1700; % layer 2 67 | priors.vsmax(2) = 1950; 68 | priors.vsmin(3) = 200; % layer 3 69 | priors.vsmax(3) = 2800; 70 | priors.vp(1) = 2500; % layer 1 fixed vp 71 | priors.vp(2) = 3810; % layer 2 fixed Vp 72 | priors.vp(3) = 4000; % layer 3 fixed Vp 73 | priors.density(1) = 0.47; % layer 1 fixed density 74 | priors.density(2) = 0.92; % layer 2 fixed density 75 | priors.density(3) = 2.5; % layer 3 fixed density 76 | elseif num_layers == 2 77 | priors.layer_depths(1) = 2 ; % layer 1 depth. 78 | priors.vsmin(1) = 500; % layer 1 79 | priors.vsmax(1) = 1700; 80 | priors.vsmin(2) = 200; % layer 3 81 | priors.vsmax(2) = 2800; 82 | priors.vp(1) = 2500; % layer 1 fixed vp 83 | priors.vp(2) = 4000; % layer 3 fixed Vp 84 | priors.density(1) = 0.47; % layer 1 fixed density 85 | priors.density(2) = 2.5; % layer 3 fixed density 86 | else % num_layers = 1 87 | priors.vsmin(1) = 200; % wide range of constraints 88 | priors.vsmax(1) = 2800; 89 | priors.vp(1) = 3500; % fixed vp 90 | priors.density(1) = 2; % fixed density 91 | end 92 | 93 | npt_init=1; % initial number of floating nuclei 94 | 95 | sigma_change_vs=20; % std deviation of Gaussian proposal on Change vs value 96 | sigma_move_depth = 1; % std deviation of Gaussian proposal on MOVE (change depth) 97 | sigma_birth_vs = 400; % std deviation of Gaussian proposal on BIRTH 98 | % (this number is also present in the DEATH 99 | % acceptance term when taking in acount the reverse jump ) 100 | 101 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 102 | % LESS IMPORTANT PARAMETERS 103 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 104 | 105 | rng('default'); 106 | rng(1); 107 | % You can change the 1 to any other number to change the seed. 108 | 109 | % Define the limits of your model 110 | x_min = priors.depth_min; 111 | x_max = priors.depth_max; 112 | dis=80; % steps to discretize the model. Trade-off between computational time and accuracy. 113 | 114 | show=10000; % show statistics of the chain every "show" samples 115 | thin = 100; % thining 116 | 117 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118 | x =linspace(x_min,x_max,dis); % discretize the model 119 | y = linspace(min(priors.vsmin), max(priors.vsmax), dis); %y limits are Vs priors limits 120 | num=ceil((nsample-burn_in)*0.025/thin); % number of collected samples 121 | 122 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 123 | % Preallocation of variables 124 | 125 | b=0; 126 | bb=0; 127 | AV=zeros(dis,1); 128 | 129 | AB=0; 130 | AD=0; 131 | PB=0; 132 | PD=0; 133 | 134 | AcV=0; 135 | PV=0; 136 | AP=0; 137 | PP=0; 138 | 139 | errors_gpdc = nan(nsample,(1 + (priors.npt_max+num_layers)*4)); 140 | best=zeros(dis,1); 141 | val_min=zeros(dis,1); 142 | val_max=zeros(dis,1); 143 | ind_min_vs=zeros(dis,1); 144 | ind_max_vs=zeros(dis,1); 145 | hist_vs=zeros(dis,1); 146 | hist_density=zeros(dis,1); 147 | hierhist=zeros(nsample,1); 148 | change_points=zeros(nsample*(priors.npt_max+num_layers),1); 149 | cov=zeros(nsample,1); 150 | nnuclei=zeros(nsample,1); 151 | sup=zeros(dis,1); 152 | inf=zeros(dis,1); 153 | MINI_vs=zeros(dis,num); 154 | MAXI_vs=zeros(dis,num); 155 | CI_density=zeros((dis-1),(dis-1)); 156 | 157 | nnucleihist=zeros(priors.npt_max+num_layers,1); 158 | nuclei_depths=zeros(priors.npt_max+num_layers,1); 159 | nuclei_vs = zeros(priors.npt_max+num_layers,1); 160 | nuclei_vp = zeros(priors.npt_max+num_layers,1); 161 | nuclei_density = zeros(priors.npt_max+num_layers,1); 162 | thickness = zeros(priors.npt_max+num_layers,1); 163 | density = zeros(priors.npt_max+num_layers,1); 164 | vs = zeros(priors.npt_max+num_layers,1); 165 | vp = zeros(priors.npt_max+num_layers,1); 166 | 167 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 168 | % Initialize - Define randomly the first model of the chain. Make sure 169 | % that it satisfies the priors. 170 | 171 | npt=npt_init; 172 | 173 | for i=1:npt+num_layers 174 | % define the layer depth. The first num_layer nuclei are special: the ith 175 | % nuclei must reside in the ith layer. 176 | 177 | if i <= num_layers 178 | if i == 1 179 | top_of_layer = priors.depth_min; 180 | if num_layers > 1 181 | bottom_of_layer = priors.layer_depths(1); 182 | else 183 | bottom_of_layer = priors.depth_max; 184 | end 185 | 186 | elseif i < num_layers 187 | top_of_layer = priors.layer_depths(i-1); 188 | bottom_of_layer = priors.layer_depths(i); 189 | else 190 | top_of_layer = priors.layer_depths(i-1); 191 | bottom_of_layer = priors.depth_max; 192 | end 193 | 194 | nuclei_depths(i)= (bottom_of_layer + top_of_layer) / 2; % fix nuclei to be in middle of layer 195 | else 196 | nuclei_depths(i)=priors.depth_min+rand*(priors.depth_max-priors.depth_min); % position of floating nuclei 197 | end 198 | 199 | % For each nuclei, find out which layer it is in: 200 | layer = num_layers; 201 | for j = 1:num_layers - 1 202 | if nuclei_depths(i) <= priors.layer_depths(j) 203 | layer = j; 204 | break 205 | end 206 | end 207 | 208 | % the variable 'layer' is the layer of the nuclei: 209 | nuclei_vs(i)=priors.vsmin(layer)+rand*(priors.vsmax(layer)-priors.vsmin(layer)); % vs 210 | nuclei_density(i)=priors.density(layer); 211 | nuclei_vp(i)=priors.vp(layer); 212 | 213 | end 214 | 215 | 216 | 217 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 218 | % COMPUTE INITIAL MISFIT 219 | % (Here, 'like' is the misfit ) 220 | like=0; 221 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths, nuclei_density, nuclei_vp, nuclei_vs, npt, num_layers, priors); 222 | 223 | %thickness(npt) = []; %remove last thickness for mat_disperse. 224 | if running_mode == 1 225 | forward_model = [freq zeros(length(data),5)]; 226 | try 227 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 228 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 229 | catch %creating error file to save varibles which do not run through the gpdc code called errors_gpdc 230 | errors_gpdc(1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [0, thickness, vp.', vs.', (density*1000).']; 231 | end %end 232 | 233 | %%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 234 | min_misfit_all_modes = NaN(length(freq),1); 235 | 236 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 237 | misfit_fm = abs(data(i) - forward_model(i,2)); 238 | misfit_m1 = abs(data(i) - forward_model(i,3)); 239 | misfit_m2 = abs(data(i) - forward_model(i,4)); 240 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 241 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 242 | if i == 1 %set first freq picked to the fundamental mode 243 | misfit_all_modes = [misfit_fm]; 244 | else 245 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 246 | end 247 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 248 | 249 | end %end multimodal misfit 250 | 251 | like = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 252 | else 253 | like = 1; 254 | end 255 | 256 | like_best=1e99; 257 | like_init=like; 258 | 259 | 260 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 261 | 262 | %%%%%%%%%%%%%%%%%% START RJ-MCMC SAMPLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 263 | 264 | fprintf('Total number of samples %i\n',nsample); 265 | fprintf('Acceptance rates:\n'); 266 | fprintf('Iteration Change Vs Move Depth Birth Death\n'); 267 | for s=1:nsample 268 | out=1; 269 | % Print statistics of the chain, The best is to "tune" these 270 | % ratios to 44 %. (Rosental 2000). 271 | if (mod(s,show)==0) 272 | number_of_samples = s; 273 | number_of_nuclei = npt; 274 | if (s>burn_in) 275 | fprintf('%7i %5.2f %5.2f %5.2f %5.2f\n',s, 100*AcV/PV, 100*AP/PP, 100*AB/PB,100*AD/PD); 276 | end 277 | end 278 | 279 | 280 | birth=0; 281 | move=0; 282 | death=0; 283 | 284 | nuclei_vs_prop=nuclei_vs; 285 | nuclei_vp_prop = nuclei_vp; 286 | nuclei_density_prop = nuclei_density; 287 | nuclei_depths_prop = nuclei_depths; 288 | 289 | like_prop = like; 290 | %---------------------------------------------------------------------- 291 | % Every even iteration, propose a new changed parameter value 292 | if (mod(s,2)==0) % Change Value 293 | if (s>burn_in) 294 | PV=PV+1; 295 | end 296 | npt_prop = npt; 297 | ind=ceil(rand*(npt+num_layers)); 298 | nuclei_vs_prop(ind) = nuclei_vs(ind) + randn * sigma_change_vs; 299 | 300 | %----------------------------------------------------------------------- 301 | % Every odd iteration change the nuclei tesselation 302 | else % Change position 303 | 304 | %u=1; % turning off birth/death 305 | u=rand; % Chose randomly between 3 different types of moves 306 | if (u<0.333) % BIRTH ++++++++++++++++++++++++++++++++++++++ 307 | birth=1; 308 | if (s>burn_in) 309 | PB=PB+1; 310 | end 311 | npt_prop = npt+1; 312 | nuclei_depths_prop(1:npt+num_layers) = nuclei_depths(1:npt+num_layers); 313 | nuclei_depths_prop(npt+num_layers+1) = priors.depth_min+rand*(priors.depth_max-priors.depth_min); 314 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),nuclei_depths_prop(npt+num_layers+1), num_layers, priors); 315 | 316 | 317 | nuclei_density_prop(npt+num_layers+1)=nuclei_density(ind); 318 | nuclei_vp_prop(npt+num_layers+1)=nuclei_vp(ind); 319 | nuclei_vs_prop(npt+num_layers+1)=nuclei_vs(ind)+randn*sigma_birth_vs; 320 | 321 | % find which layer it's in and find the product of Priors: 322 | 323 | layer = num_layers; 324 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 325 | 326 | for j = 1:num_layers - 1 327 | if nuclei_depths_prop(npt+num_layers+1) <= priors.layer_depths(j) 328 | layer = j; 329 | Prod_delta_prior = (priors.vsmax(j)-priors.vsmin(j) ); 330 | break 331 | end 332 | end 333 | 334 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(num_layers+npt+1) - nuclei_vs(ind) )^2/(2*sigma_birth_vs^2)); 335 | 336 | elseif (u<0.666) % DEATH +++++++++++++++++++++++++++++++++++++++++ 337 | death=1; 338 | if (s>burn_in) 339 | PD=PD+1; 340 | end 341 | 342 | npt_prop = npt-1; 343 | % choose a floating nuclei to remove 344 | ind=ceil(rand*npt)+num_layers; 345 | 346 | nuclei_depths_prop(1:num_layers+npt-1) = [nuclei_depths(1:ind-1) ; nuclei_depths(ind+1:num_layers+npt)]; 347 | nuclei_density_prop(1:num_layers + npt-1)= [nuclei_density(1:ind-1) ; nuclei_density(ind+1:num_layers+npt)]; 348 | nuclei_vs_prop(1:num_layers + npt-1)= [nuclei_vs(1:ind-1) ; nuclei_vs(ind+1:num_layers+npt)]; 349 | nuclei_vp_prop(1:num_layers + npt-1)= [nuclei_vp(1:ind-1) ; nuclei_vp(ind+1:num_layers+npt)]; 350 | 351 | death_pt_density = nuclei_density(ind); 352 | death_pt_vs = nuclei_vs(ind); 353 | death_pt_vp = nuclei_vp(ind); 354 | death_pt_depth = nuclei_depths(ind); 355 | 356 | 357 | %GET prob 358 | node=whichnuclei(nuclei_depths_prop(1:npt_prop+num_layers),death_pt_depth, num_layers,priors); 359 | %prob=(1/(sigmav*sqrt(2*pi)))*exp(-(pt(ind,2)-pt_prop(node,2))^2/(2*sigmav^2)); 360 | 361 | % find which layer it's in and find the product of Priors: 362 | layer = num_layers; 363 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 364 | for j = 1:num_layers - 1 365 | if death_pt_depth <= priors.layer_depths(j) 366 | layer = j; 367 | Prod_delta_prior = priors.vsmax(j)-priors.vsmin(j) ; 368 | break 369 | end 370 | end 371 | 372 | % the case of npt_prop = -1 is a rather special case but it results in an error. 373 | % when num_layers = 1. It is never excepted. 374 | if npt_prop == -1 375 | prob = 1; %set to anything. 376 | else 377 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(node) - death_pt_vs )^2/(2*sigma_birth_vs^2)); 378 | end 379 | 380 | 381 | 382 | else % MOVE +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 383 | if (s>burn_in) 384 | PP=PP+1; 385 | end 386 | move=1; 387 | npt_prop = npt; 388 | % choose the nuclei to move 389 | ind=ceil(rand*(npt+num_layers)); 390 | 391 | if num_layers == 1 || ind > num_layers %if ind is a 'floating' nuclei or depth constraints are not applied, move nuclei randomly using sigma_move_depth 392 | nuclei_depths_prop(ind) = nuclei_depths(ind)+randn*sigma_move_depth; 393 | else %if ind is a 'confined' nuclei, move nuclei randomly within the range of the layer depths 394 | if ind == 1 395 | top_of_layer = priors.depth_min; 396 | bottom_of_layer = priors.layer_depths(1); 397 | elseif ind < num_layers 398 | top_of_layer = priors.layer_depths(ind-1); 399 | bottom_of_layer = priors.layer_depths(ind); 400 | else 401 | top_of_layer = priors.layer_depths(ind-1); 402 | bottom_of_layer = priors.depth_max; 403 | end 404 | nuclei_depths_prop(ind) = (bottom_of_layer-top_of_layer).*rand(1) + top_of_layer; 405 | end 406 | 407 | % Find move probability 408 | 409 | % find which layer the nuclei is currently in: 410 | layer = num_layers; 411 | move_prob1 = priors.vsmax(layer)-priors.vsmin(layer); 412 | for j = 1:num_layers - 1 413 | if nuclei_depths(ind) <= priors.layer_depths(j) 414 | layer = j; 415 | move_prob1 = priors.vsmax(j)-priors.vsmin(j) ; 416 | break 417 | end 418 | end 419 | 420 | % find which layer the nuclei will move to: 421 | layer = num_layers; 422 | move_prob2 = priors.vsmax(layer)-priors.vsmin(layer); 423 | for j = 1:num_layers - 1 424 | if nuclei_depths_prop(ind) <= priors.layer_depths(j) 425 | layer = j; 426 | move_prob2 = priors.vsmax(j)-priors.vsmin(j) ; 427 | break 428 | end 429 | end 430 | move_prob = move_prob1 / move_prob2; 431 | 432 | end 433 | 434 | end % Change the position 435 | %---------------------------------------------------------------------- 436 | 437 | 438 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439 | % COMPUTE MISFIT OF THE PROPOSED MODEL 440 | % If the proposed model is not outside the bounds of the uniform prior, 441 | % compute its misfit : "like_prop" 442 | if out==1 443 | like_prop=0; 444 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths_prop, nuclei_density_prop, nuclei_vp_prop, nuclei_vs_prop, npt_prop, num_layers, priors); 445 | 446 | if priors_OK == 0 447 | out = 0; 448 | like_prop = 0; 449 | else 450 | 451 | if running_mode == 1 452 | forward_model = [freq zeros(length(data),5)]; 453 | try 454 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 455 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 456 | catch 457 | errors_gpdc(s+1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [s, thickness, vp.', vs.', (density*1000).']; 458 | end %end 459 | 460 | %%%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 461 | min_misfit_all_modes = NaN(length(freq),1); 462 | 463 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 464 | 465 | misfit_fm = abs(data(i) - forward_model(i,2)); 466 | misfit_m1 = abs(data(i) - forward_model(i,3)); 467 | misfit_m2 = abs(data(i) - forward_model(i,4)); 468 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 469 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 470 | if i == 1 %set first freq picked to the fundamental mode 471 | misfit_all_modes = [misfit_fm]; 472 | else 473 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 474 | end 475 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 476 | end 477 | %end 478 | like_prop = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 479 | else 480 | like_prop = 1; 481 | end 482 | end 483 | 484 | end %if (out==1) 485 | 486 | 487 | 488 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 489 | %%% SEE WHETHER MODEL IS ACCEPTED 490 | 491 | accept=0; 492 | % This avoids runtime errors, as if out=0 Matlab insists on evaluating 493 | % Prod_delta_prior even though it never affects the calculation if out==0 494 | % (for the result is always 0). 495 | 496 | if out == 0 497 | Prod_delta_prior = 1; 498 | prob = 1; 499 | end 500 | 501 | % THe acceptance term takes different 502 | % values according the the proposal that has been made. 503 | 504 | if (birth==1) 505 | if (rand<((1/(Prod_delta_prior*prob))*exp(log(out)-like_prop+like))) 506 | accept=1; 507 | if (s>burn_in) 508 | AB=AB+1; 509 | end 510 | end 511 | elseif (death==1) 512 | 513 | if (rand<(Prod_delta_prior*prob*exp(log(out)-like_prop+like))) 514 | accept=1; 515 | if (s>burn_in) 516 | AD=AD+1; 517 | end 518 | end 519 | 520 | elseif (move == 1) % NO JUMP, i.e no change in dimension 521 | 522 | if (rand<(move_prob * exp(log(out)-like_prop+like))) 523 | accept=1; 524 | if (s>burn_in) 525 | AP=AP+1; 526 | end %if (s>burn_in) 527 | end 528 | 529 | else %change v_s 530 | if (randburn_in) 533 | AcV=AcV+1; 534 | end %if (s>burn_in) 535 | end 536 | end 537 | 538 | % If accept, update the values 539 | if (accept==1) 540 | npt=npt_prop; 541 | nuclei_depths = nuclei_depths_prop; 542 | nuclei_density = nuclei_density_prop; 543 | nuclei_vs = nuclei_vs_prop; 544 | nuclei_vp = nuclei_vp_prop; 545 | like=like_prop; 546 | end 547 | for i=1:dis 548 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),x(i),num_layers,priors); 549 | hist_vs(i)=nuclei_vs(ind); 550 | end 551 | [N]=histcounts2(x,hist_vs',x,y); 552 | vs_edge=y(1:(dis-1)); 553 | depth_edge=x(1:(dis-1)); 554 | 555 | 556 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 557 | % We collect the samples for the ensemble solution 558 | 559 | if (s>burn_in) 560 | if (mod(s,thin)==0) 561 | b=b+1; 562 | % DO THE AVERAGE 563 | 564 | for i=1:dis 565 | ind=whichnuclei(nuclei_depths,x(i), num_layers,priors); 566 | 567 | AV(i,1)=AV(i,1)+nuclei_vs(ind); 568 | 569 | % Do the 95% credible interval for vs 570 | if (b<=num) 571 | MINI_vs(i,b)=nuclei_vs(ind); 572 | MAXI_vs(i,b)=nuclei_vs(ind); 573 | if (b==num) 574 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 575 | [val_max_vs(i) ind_max_vs(i)]=max(MINI_vs(i,:)); 576 | end 577 | 578 | else 579 | if (nuclei_vs(ind)>val_min_vs(i)) 580 | MAXI_vs(i,ind_min_vs(i))=nuclei_vs(ind); 581 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 582 | end 583 | if (nuclei_vs(ind) find posterior; 0 -> Find priors. 36 | 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | % VERY IMPORTANT PARAMETERS 39 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%th 40 | 41 | burn_in=10000; % burn-in period 42 | nsample=1000000; % total number of samples 43 | 44 | %Uniform prior on depths for nuclei 45 | priors.depth_min=0; % Cannot be changed, always from the surface. 46 | priors.depth_max=40; 47 | priors.npt_max = 30; 48 | priors.npt_min = 0; 49 | 50 | num_layers = 3; 51 | 52 | priors.layer_depths = zeros(num_layers-1,1); %the last layer depth is infinity (and is not defined). 53 | priors.vsmin = zeros(num_layers,1); 54 | priors.vsmax = zeros(num_layers,1); 55 | priors.vp = zeros(num_layers,1); 56 | priors.density = zeros(num_layers,1); 57 | 58 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | % Define the priors and layer geometry 60 | if num_layers == 3 61 | priors.layer_depths(1) = 2 ; % snow depth. 62 | priors.layer_depths(2) = 25.5 ; % ice depth. 63 | priors.vsmin(1) = 500; % Snow 64 | priors.vsmax(1) = 1700; 65 | priors.vsmin(2) = 1700; % Ice 66 | priors.vsmax(2) = 1950; 67 | priors.vsmin(3) = 200; % rock 68 | priors.vsmax(3) = 2800; 69 | priors.vp(1) = 2500; % snow fixed vp 70 | priors.vp(2) = 3810; % ice fixed Vp 71 | priors.vp(3) = 4000; % rock fixed Vp 72 | priors.density(1) = 0.47; % snow fixed density 73 | priors.density(2) = 0.92; % ice fixed density 74 | priors.density(3) = 2.5; % rock fixed density 75 | elseif num_layers == 2 76 | priors.layer_depths(1) = 2 ; % snow depth. 77 | priors.vsmin(1) = 500; % Snow 78 | priors.vsmax(1) = 1700; 79 | priors.vsmin(2) = 200; % rock 80 | priors.vsmax(2) = 2800; 81 | priors.vp(1) = 2500; % snow fixed vp 82 | priors.vp(2) = 4000; % rock fixed Vp 83 | priors.density(1) = 0.47; % snow fixed density 84 | priors.density(2) = 2.5; % rock fixed density 85 | else % num_layers = 1 86 | priors.vsmin(1) = 200; % wide range of constraints 87 | priors.vsmax(1) = 2800; 88 | priors.vp(1) = 3500; % fixed vp 89 | priors.density(1) = 2; % fixed density 90 | end 91 | 92 | npt_init=1; % initial number of floating nuclei 93 | 94 | sigma_change_vs=20; % std deviation of Gaussian proposal on Change vs value 95 | sigma_move_depth = 1; % std deviation of Gaussian proposal on MOVE (change depth) 96 | sigma_birth_vs = 400; % std deviation of Gaussian proposal on BIRTH 97 | % (this number is also present in the DEATH 98 | % acceptance term when taking in acount the reverse jump ) 99 | 100 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101 | % LESS IMPORTANT PARAMETERS 102 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 103 | 104 | rng('default'); 105 | rng(2); 106 | % You can change the 1 to any other number to change the seed. 107 | 108 | % Define the limits of your model 109 | x_min = priors.depth_min; 110 | x_max = priors.depth_max; 111 | dis=80; % steps to discretize the model. Trade-off between computational time and accuracy. 112 | 113 | show=10000; % show statistics of the chain every "show" samples 114 | thin = 100; % thining 115 | 116 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117 | x =linspace(x_min,x_max,dis); % discretize the model 118 | y = linspace(min(priors.vsmin), max(priors.vsmax), dis); %y limits are Vs priors limits 119 | num=ceil((nsample-burn_in)*0.025/thin); % number of collected samples 120 | 121 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 122 | % Preallocation of variables 123 | 124 | b=0; 125 | bb=0; 126 | AV=zeros(dis,1); 127 | 128 | AB=0; 129 | AD=0; 130 | PB=0; 131 | PD=0; 132 | 133 | AcV=0; 134 | PV=0; 135 | AP=0; 136 | PP=0; 137 | 138 | errors_gpdc = nan(nsample,(1 + (priors.npt_max+num_layers)*4)); 139 | best=zeros(dis,1); 140 | val_min=zeros(dis,1); 141 | val_max=zeros(dis,1); 142 | ind_min_vs=zeros(dis,1); 143 | ind_max_vs=zeros(dis,1); 144 | hist_vs=zeros(dis,1); 145 | hist_density=zeros(dis,1); 146 | hierhist=zeros(nsample,1); 147 | change_points=zeros(nsample*(priors.npt_max+num_layers),1); 148 | cov=zeros(nsample,1); 149 | nnuclei=zeros(nsample,1); 150 | sup=zeros(dis,1); 151 | inf=zeros(dis,1); 152 | MINI_vs=zeros(dis,num); 153 | MAXI_vs=zeros(dis,num); 154 | CI_density=zeros((dis-1),(dis-1)); 155 | 156 | nnucleihist=zeros(priors.npt_max+num_layers,1); 157 | nuclei_depths=zeros(priors.npt_max+num_layers,1); 158 | nuclei_vs = zeros(priors.npt_max+num_layers,1); 159 | nuclei_vp = zeros(priors.npt_max+num_layers,1); 160 | nuclei_density = zeros(priors.npt_max+num_layers,1); 161 | thickness = zeros(priors.npt_max+num_layers,1); 162 | density = zeros(priors.npt_max+num_layers,1); 163 | vs = zeros(priors.npt_max+num_layers,1); 164 | vp = zeros(priors.npt_max+num_layers,1); 165 | 166 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167 | % Initialize - Define randomly the first model of the chain. Make sure 168 | % that it satisfies the priors. 169 | 170 | npt=npt_init; 171 | 172 | for i=1:npt+num_layers 173 | % define the layer depth. The first num_layer nuclei are special: the ith 174 | % nuclei must reside in the ith layer. 175 | 176 | if i <= num_layers 177 | if i == 1 178 | top_of_layer = priors.depth_min; 179 | if num_layers > 1 180 | bottom_of_layer = priors.layer_depths(1); 181 | else 182 | bottom_of_layer = priors.depth_max; 183 | end 184 | 185 | elseif i < num_layers 186 | top_of_layer = priors.layer_depths(i-1); 187 | bottom_of_layer = priors.layer_depths(i); 188 | else 189 | top_of_layer = priors.layer_depths(i-1); 190 | bottom_of_layer = priors.depth_max; 191 | end 192 | 193 | nuclei_depths(i)= (bottom_of_layer + top_of_layer) / 2; % fix nuclei to be in middle of layer 194 | else 195 | nuclei_depths(i)=priors.depth_min+rand*(priors.depth_max-priors.depth_min); % position of floating nuclei 196 | end 197 | 198 | % For each nuclei, find out which layer it is in: 199 | layer = num_layers; 200 | for j = 1:num_layers - 1 201 | if nuclei_depths(i) <= priors.layer_depths(j) 202 | layer = j; 203 | break 204 | end 205 | end 206 | 207 | % the variable 'layer' is the layer of the nuclei: 208 | nuclei_vs(i)=priors.vsmin(layer)+rand*(priors.vsmax(layer)-priors.vsmin(layer)); % vs 209 | nuclei_density(i)=priors.density(layer); 210 | nuclei_vp(i)=priors.vp(layer); 211 | 212 | end 213 | 214 | 215 | 216 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 217 | % COMPUTE INITIAL MISFIT 218 | % (Here, 'like' is the misfit ) 219 | like=0; 220 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths, nuclei_density, nuclei_vp, nuclei_vs, npt, num_layers, priors); 221 | 222 | %thickness(npt) = []; %remove last thickness for mat_disperse. 223 | if running_mode == 1 224 | forward_model = [freq zeros(length(data),5)]; 225 | try 226 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 227 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 228 | catch %creating error file to save varibles which do not run through the gpdc code called errors_gpdc 229 | errors_gpdc(1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [0, thickness, vp.', vs.', (density*1000).']; 230 | end %end 231 | 232 | %%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 233 | min_misfit_all_modes = NaN(length(freq),1); 234 | 235 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 236 | misfit_fm = abs(data(i) - forward_model(i,2)); 237 | misfit_m1 = abs(data(i) - forward_model(i,3)); 238 | misfit_m2 = abs(data(i) - forward_model(i,4)); 239 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 240 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 241 | if i == 1 %set first freq picked to the fundamental mode 242 | misfit_all_modes = [misfit_fm]; 243 | else 244 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 245 | end 246 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 247 | 248 | end %end multimodal misfit 249 | 250 | like = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 251 | else 252 | like = 1; 253 | end 254 | 255 | like_best=1e99; 256 | like_init=like; 257 | 258 | 259 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 260 | 261 | %%%%%%%%%%%%%%%%%% START RJ-MCMC SAMPLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 262 | 263 | fprintf('Total number of samples %i\n',nsample); 264 | fprintf('Acceptance rates:\n'); 265 | fprintf('Iteration Change Vs Move Depth Birth Death\n'); 266 | for s=1:nsample 267 | out=1; 268 | % Print statistics of the chain, The best is to "tune" these 269 | % ratios to 44 %. (Rosental 2000). 270 | if (mod(s,show)==0) 271 | number_of_samples = s; 272 | number_of_nuclei = npt; 273 | if (s>burn_in) 274 | fprintf('%7i %5.2f %5.2f %5.2f %5.2f\n',s, 100*AcV/PV, 100*AP/PP, 100*AB/PB,100*AD/PD); 275 | end 276 | end 277 | 278 | 279 | birth=0; 280 | move=0; 281 | death=0; 282 | 283 | nuclei_vs_prop=nuclei_vs; 284 | nuclei_vp_prop = nuclei_vp; 285 | nuclei_density_prop = nuclei_density; 286 | nuclei_depths_prop = nuclei_depths; 287 | 288 | like_prop = like; 289 | %---------------------------------------------------------------------- 290 | % Every even iteration, propose a new changed parameter value 291 | if (mod(s,2)==0) % Change Value 292 | if (s>burn_in) 293 | PV=PV+1; 294 | end 295 | npt_prop = npt; 296 | ind=ceil(rand*(npt+num_layers)); 297 | nuclei_vs_prop(ind) = nuclei_vs(ind) + randn * sigma_change_vs; 298 | 299 | %----------------------------------------------------------------------- 300 | % Every odd iteration change the nuclei tesselation 301 | else % Change position 302 | 303 | %u=1; % turning off birth/death 304 | u=rand; % Chose randomly between 3 different types of moves 305 | if (u<0.333) % BIRTH ++++++++++++++++++++++++++++++++++++++ 306 | birth=1; 307 | if (s>burn_in) 308 | PB=PB+1; 309 | end 310 | npt_prop = npt+1; 311 | nuclei_depths_prop(1:npt+num_layers) = nuclei_depths(1:npt+num_layers); 312 | nuclei_depths_prop(npt+num_layers+1) = priors.depth_min+rand*(priors.depth_max-priors.depth_min); 313 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),nuclei_depths_prop(npt+num_layers+1), num_layers, priors); 314 | 315 | 316 | nuclei_density_prop(npt+num_layers+1)=nuclei_density(ind); 317 | nuclei_vp_prop(npt+num_layers+1)=nuclei_vp(ind); 318 | nuclei_vs_prop(npt+num_layers+1)=nuclei_vs(ind)+randn*sigma_birth_vs; 319 | 320 | % find which layer it's in and find the product of Priors: 321 | 322 | layer = num_layers; 323 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 324 | 325 | for j = 1:num_layers - 1 326 | if nuclei_depths_prop(npt+num_layers+1) <= priors.layer_depths(j) 327 | layer = j; 328 | Prod_delta_prior = (priors.vsmax(j)-priors.vsmin(j) ); 329 | break 330 | end 331 | end 332 | 333 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(num_layers+npt+1) - nuclei_vs(ind) )^2/(2*sigma_birth_vs^2)); 334 | 335 | elseif (u<0.666) % DEATH +++++++++++++++++++++++++++++++++++++++++ 336 | death=1; 337 | if (s>burn_in) 338 | PD=PD+1; 339 | end 340 | 341 | npt_prop = npt-1; 342 | % choose a floating nuclei to remove 343 | ind=ceil(rand*npt)+num_layers; 344 | 345 | nuclei_depths_prop(1:num_layers+npt-1) = [nuclei_depths(1:ind-1) ; nuclei_depths(ind+1:num_layers+npt)]; 346 | nuclei_density_prop(1:num_layers + npt-1)= [nuclei_density(1:ind-1) ; nuclei_density(ind+1:num_layers+npt)]; 347 | nuclei_vs_prop(1:num_layers + npt-1)= [nuclei_vs(1:ind-1) ; nuclei_vs(ind+1:num_layers+npt)]; 348 | nuclei_vp_prop(1:num_layers + npt-1)= [nuclei_vp(1:ind-1) ; nuclei_vp(ind+1:num_layers+npt)]; 349 | 350 | death_pt_density = nuclei_density(ind); 351 | death_pt_vs = nuclei_vs(ind); 352 | death_pt_vp = nuclei_vp(ind); 353 | death_pt_depth = nuclei_depths(ind); 354 | 355 | 356 | %GET prob 357 | node=whichnuclei(nuclei_depths_prop(1:npt_prop+num_layers),death_pt_depth, num_layers,priors); 358 | %prob=(1/(sigmav*sqrt(2*pi)))*exp(-(pt(ind,2)-pt_prop(node,2))^2/(2*sigmav^2)); 359 | 360 | % find which layer it's in and find the product of Priors: 361 | layer = num_layers; 362 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 363 | for j = 1:num_layers - 1 364 | if death_pt_depth <= priors.layer_depths(j) 365 | layer = j; 366 | Prod_delta_prior = priors.vsmax(j)-priors.vsmin(j) ; 367 | break 368 | end 369 | end 370 | 371 | % the case of npt_prop = -1 is a rather special case but it results in an error. 372 | % when num_layers = 1. It is never excepted. 373 | if npt_prop == -1 374 | prob = 1; %set to anything. 375 | else 376 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(node) - death_pt_vs )^2/(2*sigma_birth_vs^2)); 377 | end 378 | 379 | 380 | 381 | else % MOVE +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 382 | if (s>burn_in) 383 | PP=PP+1; 384 | end 385 | move=1; 386 | npt_prop = npt; 387 | % choose the nuclei to move 388 | ind=ceil(rand*(npt+num_layers)); 389 | 390 | if num_layers == 1 || ind > num_layers %if ind is a 'floating' nuclei or depth constraints are not applied, move nuclei randomly using sigma_move_depth 391 | nuclei_depths_prop(ind) = nuclei_depths(ind)+randn*sigma_move_depth; 392 | else %if ind is a 'confined' nuclei, move nuclei randomly within the range of the layer depths 393 | if ind == 1 394 | top_of_layer = priors.depth_min; 395 | bottom_of_layer = priors.layer_depths(1); 396 | elseif ind < num_layers 397 | top_of_layer = priors.layer_depths(ind-1); 398 | bottom_of_layer = priors.layer_depths(ind); 399 | else 400 | top_of_layer = priors.layer_depths(ind-1); 401 | bottom_of_layer = priors.depth_max; 402 | end 403 | nuclei_depths_prop(ind) = (bottom_of_layer-top_of_layer).*rand(1) + top_of_layer; 404 | end 405 | 406 | % Find move probability 407 | 408 | % find which layer the nuclei is currently in: 409 | layer = num_layers; 410 | move_prob1 = priors.vsmax(layer)-priors.vsmin(layer); 411 | for j = 1:num_layers - 1 412 | if nuclei_depths(ind) <= priors.layer_depths(j) 413 | layer = j; 414 | move_prob1 = priors.vsmax(j)-priors.vsmin(j) ; 415 | break 416 | end 417 | end 418 | 419 | % find which layer the nuclei will move to: 420 | layer = num_layers; 421 | move_prob2 = priors.vsmax(layer)-priors.vsmin(layer); 422 | for j = 1:num_layers - 1 423 | if nuclei_depths_prop(ind) <= priors.layer_depths(j) 424 | layer = j; 425 | move_prob2 = priors.vsmax(j)-priors.vsmin(j) ; 426 | break 427 | end 428 | end 429 | move_prob = move_prob1 / move_prob2; 430 | 431 | end 432 | 433 | end % Change the position 434 | %---------------------------------------------------------------------- 435 | 436 | 437 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 438 | % COMPUTE MISFIT OF THE PROPOSED MODEL 439 | % If the proposed model is not outside the bounds of the uniform prior, 440 | % compute its misfit : "like_prop" 441 | if out==1 442 | like_prop=0; 443 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths_prop, nuclei_density_prop, nuclei_vp_prop, nuclei_vs_prop, npt_prop, num_layers, priors); 444 | 445 | if priors_OK == 0 446 | out = 0; 447 | like_prop = 0; 448 | else 449 | 450 | if running_mode == 1 451 | forward_model = [freq zeros(length(data),5)]; 452 | try 453 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 454 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 455 | catch 456 | errors_gpdc(s+1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [s, thickness, vp.', vs.', (density*1000).']; 457 | end %end 458 | 459 | %%%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 460 | min_misfit_all_modes = NaN(length(freq),1); 461 | 462 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 463 | 464 | misfit_fm = abs(data(i) - forward_model(i,2)); 465 | misfit_m1 = abs(data(i) - forward_model(i,3)); 466 | misfit_m2 = abs(data(i) - forward_model(i,4)); 467 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 468 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 469 | if i == 1 %set first freq picked to the fundamental mode 470 | misfit_all_modes = [misfit_fm]; 471 | else 472 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 473 | end 474 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 475 | end 476 | %end 477 | like_prop = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 478 | else 479 | like_prop = 1; 480 | end 481 | end 482 | 483 | end %if (out==1) 484 | 485 | 486 | 487 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 488 | %%% SEE WHETHER MODEL IS ACCEPTED 489 | 490 | accept=0; 491 | % This avoids runtime errors, as if out=0 Matlab insists on evaluating 492 | % Prod_delta_prior even though it never affects the calculation if out==0 493 | % (for the result is always 0). 494 | 495 | if out == 0 496 | Prod_delta_prior = 1; 497 | prob = 1; 498 | end 499 | 500 | % THe acceptance term takes different 501 | % values according the the proposal that has been made. 502 | 503 | if (birth==1) 504 | if (rand<((1/(Prod_delta_prior*prob))*exp(log(out)-like_prop+like))) 505 | accept=1; 506 | if (s>burn_in) 507 | AB=AB+1; 508 | end 509 | end 510 | elseif (death==1) 511 | 512 | if (rand<(Prod_delta_prior*prob*exp(log(out)-like_prop+like))) 513 | accept=1; 514 | if (s>burn_in) 515 | AD=AD+1; 516 | end 517 | end 518 | 519 | elseif (move == 1) % NO JUMP, i.e no change in dimension 520 | 521 | if (rand<(move_prob * exp(log(out)-like_prop+like))) 522 | accept=1; 523 | if (s>burn_in) 524 | AP=AP+1; 525 | end %if (s>burn_in) 526 | end 527 | 528 | else %change v_s 529 | if (randburn_in) 532 | AcV=AcV+1; 533 | end %if (s>burn_in) 534 | end 535 | end 536 | 537 | % If accept, update the values 538 | if (accept==1) 539 | npt=npt_prop; 540 | nuclei_depths = nuclei_depths_prop; 541 | nuclei_density = nuclei_density_prop; 542 | nuclei_vs = nuclei_vs_prop; 543 | nuclei_vp = nuclei_vp_prop; 544 | like=like_prop; 545 | end 546 | for i=1:dis 547 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),x(i),num_layers,priors); 548 | hist_vs(i)=nuclei_vs(ind); 549 | end 550 | [N]=histcounts2(x,hist_vs',x,y); 551 | vs_edge=y(1:(dis-1)); 552 | depth_edge=x(1:(dis-1)); 553 | 554 | 555 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 556 | % We collect the samples for the ensemble solution 557 | 558 | if (s>burn_in) 559 | if (mod(s,thin)==0) 560 | b=b+1; 561 | % DO THE AVERAGE 562 | 563 | for i=1:dis 564 | ind=whichnuclei(nuclei_depths,x(i), num_layers,priors); 565 | 566 | AV(i,1)=AV(i,1)+nuclei_vs(ind); 567 | 568 | % Do the 95% credible interval for vs 569 | if (b<=num) 570 | MINI_vs(i,b)=nuclei_vs(ind); 571 | MAXI_vs(i,b)=nuclei_vs(ind); 572 | if (b==num) 573 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 574 | [val_max_vs(i) ind_max_vs(i)]=max(MINI_vs(i,:)); 575 | end 576 | 577 | else 578 | if (nuclei_vs(ind)>val_min_vs(i)) 579 | MAXI_vs(i,ind_min_vs(i))=nuclei_vs(ind); 580 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 581 | end 582 | if (nuclei_vs(ind) find posterior; 0 -> Find priors. 36 | 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | % VERY IMPORTANT PARAMETERS 39 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%th 40 | 41 | burn_in=10000; % burn-in period 42 | nsample=1000000; % total number of samples 43 | 44 | %Uniform prior on depths for nuclei 45 | priors.depth_min=0; % Cannot be changed, always from the surface. 46 | priors.depth_max=40; 47 | priors.npt_max = 30; 48 | priors.npt_min = 0; 49 | 50 | num_layers = 3; 51 | 52 | priors.layer_depths = zeros(num_layers-1,1); %the last layer depth is infinity (and is not defined). 53 | priors.vsmin = zeros(num_layers,1); 54 | priors.vsmax = zeros(num_layers,1); 55 | priors.vp = zeros(num_layers,1); 56 | priors.density = zeros(num_layers,1); 57 | 58 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | % Define the priors and layer geometry 60 | if num_layers == 3 61 | priors.layer_depths(1) = 2 ; % snow depth. 62 | priors.layer_depths(2) = 25.5 ; % ice depth. 63 | priors.vsmin(1) = 500; % Snow 64 | priors.vsmax(1) = 1700; 65 | priors.vsmin(2) = 1700; % Ice 66 | priors.vsmax(2) = 1950; 67 | priors.vsmin(3) = 200; % rock 68 | priors.vsmax(3) = 2800; 69 | priors.vp(1) = 2500; % snow fixed vp 70 | priors.vp(2) = 3810; % ice fixed Vp 71 | priors.vp(3) = 4000; % rock fixed Vp 72 | priors.density(1) = 0.47; % snow fixed density 73 | priors.density(2) = 0.92; % ice fixed density 74 | priors.density(3) = 2.5; % rock fixed density 75 | elseif num_layers == 2 76 | priors.layer_depths(1) = 2 ; % snow depth. 77 | priors.vsmin(1) = 500; % Snow 78 | priors.vsmax(1) = 1700; 79 | priors.vsmin(2) = 200; % rock 80 | priors.vsmax(2) = 2800; 81 | priors.vp(1) = 2500; % snow fixed vp 82 | priors.vp(2) = 4000; % rock fixed Vp 83 | priors.density(1) = 0.47; % snow fixed density 84 | priors.density(2) = 2.5; % rock fixed density 85 | else % num_layers = 1 86 | priors.vsmin(1) = 200; % wide range of constraints 87 | priors.vsmax(1) = 2800; 88 | priors.vp(1) = 3500; % fixed vp 89 | priors.density(1) = 2; % fixed density 90 | end 91 | 92 | npt_init=1; % initial number of floating nuclei 93 | 94 | sigma_change_vs=20; % std deviation of Gaussian proposal on Change vs value 95 | sigma_move_depth = 1; % std deviation of Gaussian proposal on MOVE (change depth) 96 | sigma_birth_vs = 400; % std deviation of Gaussian proposal on BIRTH 97 | % (this number is also present in the DEATH 98 | % acceptance term when taking in acount the reverse jump ) 99 | 100 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101 | % LESS IMPORTANT PARAMETERS 102 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 103 | 104 | rng('default'); 105 | rng(1); 106 | % You can change the 1 to any other number to change the seed. 107 | 108 | % Define the limits of your model 109 | x_min = priors.depth_min; 110 | x_max = priors.depth_max; 111 | dis=80; % steps to discretize the model. Trade-off between computational time and accuracy. 112 | 113 | show=10000; % show statistics of the chain every "show" samples 114 | thin = 100; % thining 115 | 116 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117 | x =linspace(x_min,x_max,dis); % discretize the model 118 | y = linspace(min(priors.vsmin), max(priors.vsmax), dis); %y limits are Vs priors limits 119 | num=ceil((nsample-burn_in)*0.025/thin); % number of collected samples 120 | 121 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 122 | % Preallocation of variables 123 | 124 | b=0; 125 | bb=0; 126 | AV=zeros(dis,1); 127 | 128 | AB=0; 129 | AD=0; 130 | PB=0; 131 | PD=0; 132 | 133 | AcV=0; 134 | PV=0; 135 | AP=0; 136 | PP=0; 137 | 138 | errors_gpdc = nan(nsample,(1 + (priors.npt_max+num_layers)*4)); 139 | best=zeros(dis,1); 140 | val_min=zeros(dis,1); 141 | val_max=zeros(dis,1); 142 | ind_min_vs=zeros(dis,1); 143 | ind_max_vs=zeros(dis,1); 144 | hist_vs=zeros(dis,1); 145 | hist_density=zeros(dis,1); 146 | hierhist=zeros(nsample,1); 147 | change_points=zeros(nsample*(priors.npt_max+num_layers),1); 148 | cov=zeros(nsample,1); 149 | nnuclei=zeros(nsample,1); 150 | sup=zeros(dis,1); 151 | inf=zeros(dis,1); 152 | MINI_vs=zeros(dis,num); 153 | MAXI_vs=zeros(dis,num); 154 | CI_density=zeros((dis-1),(dis-1)); 155 | 156 | nnucleihist=zeros(priors.npt_max+num_layers,1); 157 | nuclei_depths=zeros(priors.npt_max+num_layers,1); 158 | nuclei_vs = zeros(priors.npt_max+num_layers,1); 159 | nuclei_vp = zeros(priors.npt_max+num_layers,1); 160 | nuclei_density = zeros(priors.npt_max+num_layers,1); 161 | thickness = zeros(priors.npt_max+num_layers,1); 162 | density = zeros(priors.npt_max+num_layers,1); 163 | vs = zeros(priors.npt_max+num_layers,1); 164 | vp = zeros(priors.npt_max+num_layers,1); 165 | 166 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167 | % Initialize - Define randomly the first model of the chain. Make sure 168 | % that it satisfies the priors. 169 | 170 | npt=npt_init; 171 | 172 | for i=1:npt+num_layers 173 | % define the layer depth. The first num_layer nuclei are special: the ith 174 | % nuclei must reside in the ith layer. 175 | 176 | if i <= num_layers 177 | if i == 1 178 | top_of_layer = priors.depth_min; 179 | if num_layers > 1 180 | bottom_of_layer = priors.layer_depths(1); 181 | else 182 | bottom_of_layer = priors.depth_max; 183 | end 184 | 185 | elseif i < num_layers 186 | top_of_layer = priors.layer_depths(i-1); 187 | bottom_of_layer = priors.layer_depths(i); 188 | else 189 | top_of_layer = priors.layer_depths(i-1); 190 | bottom_of_layer = priors.depth_max; 191 | end 192 | 193 | nuclei_depths(i)= (bottom_of_layer + top_of_layer) / 2; % fix nuclei to be in middle of layer 194 | else 195 | nuclei_depths(i)=priors.depth_min+rand*(priors.depth_max-priors.depth_min); % position of floating nuclei 196 | end 197 | 198 | % For each nuclei, find out which layer it is in: 199 | layer = num_layers; 200 | for j = 1:num_layers - 1 201 | if nuclei_depths(i) <= priors.layer_depths(j) 202 | layer = j; 203 | break 204 | end 205 | end 206 | 207 | % the variable 'layer' is the layer of the nuclei: 208 | nuclei_vs(i)=priors.vsmin(layer)+rand*(priors.vsmax(layer)-priors.vsmin(layer)); % vs 209 | nuclei_density(i)=priors.density(layer); 210 | nuclei_vp(i)=priors.vp(layer); 211 | 212 | end 213 | 214 | 215 | 216 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 217 | % COMPUTE INITIAL MISFIT 218 | % (Here, 'like' is the misfit ) 219 | like=0; 220 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths, nuclei_density, nuclei_vp, nuclei_vs, npt, num_layers, priors); 221 | 222 | %thickness(npt) = []; %remove last thickness for mat_disperse. 223 | if running_mode == 1 224 | forward_model = [freq zeros(length(data),5)]; 225 | try 226 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 227 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 228 | catch %creating error file to save varibles which do not run through the gpdc code called errors_gpdc 229 | errors_gpdc(1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [0, thickness, vp.', vs.', (density*1000).']; 230 | end %end 231 | 232 | %%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 233 | min_misfit_all_modes = NaN(length(freq),1); 234 | 235 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 236 | misfit_fm = abs(data(i) - forward_model(i,2)); 237 | misfit_m1 = abs(data(i) - forward_model(i,3)); 238 | misfit_m2 = abs(data(i) - forward_model(i,4)); 239 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 240 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 241 | if i == 17 %set first freq picked to the fundamental mode 242 | misfit_all_modes = [misfit_fm]; 243 | else 244 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 245 | end 246 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 247 | 248 | end %end multimodal misfit 249 | 250 | like = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 251 | else 252 | like = 1; 253 | end 254 | 255 | like_best=1e99; 256 | like_init=like; 257 | 258 | 259 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 260 | 261 | %%%%%%%%%%%%%%%%%% START RJ-MCMC SAMPLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 262 | 263 | fprintf('Total number of samples %i\n',nsample); 264 | fprintf('Acceptance rates:\n'); 265 | fprintf('Iteration Change Vs Move Depth Birth Death\n'); 266 | for s=1:nsample 267 | out=1; 268 | % Print statistics of the chain, The best is to "tune" these 269 | % ratios to 44 %. (Rosental 2000). 270 | if (mod(s,show)==0) 271 | number_of_samples = s; 272 | number_of_nuclei = npt; 273 | if (s>burn_in) 274 | fprintf('%7i %5.2f %5.2f %5.2f %5.2f\n',s, 100*AcV/PV, 100*AP/PP, 100*AB/PB,100*AD/PD); 275 | end 276 | end 277 | 278 | 279 | birth=0; 280 | move=0; 281 | death=0; 282 | 283 | nuclei_vs_prop=nuclei_vs; 284 | nuclei_vp_prop = nuclei_vp; 285 | nuclei_density_prop = nuclei_density; 286 | nuclei_depths_prop = nuclei_depths; 287 | 288 | like_prop = like; 289 | %---------------------------------------------------------------------- 290 | % Every even iteration, propose a new changed parameter value 291 | if (mod(s,2)==0) % Change Value 292 | if (s>burn_in) 293 | PV=PV+1; 294 | end 295 | npt_prop = npt; 296 | ind=ceil(rand*(npt+num_layers)); 297 | nuclei_vs_prop(ind) = nuclei_vs(ind) + randn * sigma_change_vs; 298 | 299 | %----------------------------------------------------------------------- 300 | % Every odd iteration change the nuclei tesselation 301 | else % Change position 302 | 303 | %u=1; % turning off birth/death 304 | u=rand; % Chose randomly between 3 different types of moves 305 | if (u<0.333) % BIRTH ++++++++++++++++++++++++++++++++++++++ 306 | birth=1; 307 | if (s>burn_in) 308 | PB=PB+1; 309 | end 310 | npt_prop = npt+1; 311 | nuclei_depths_prop(1:npt+num_layers) = nuclei_depths(1:npt+num_layers); 312 | nuclei_depths_prop(npt+num_layers+1) = priors.depth_min+rand*(priors.depth_max-priors.depth_min); 313 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),nuclei_depths_prop(npt+num_layers+1), num_layers, priors); 314 | 315 | 316 | nuclei_density_prop(npt+num_layers+1)=nuclei_density(ind); 317 | nuclei_vp_prop(npt+num_layers+1)=nuclei_vp(ind); 318 | nuclei_vs_prop(npt+num_layers+1)=nuclei_vs(ind)+randn*sigma_birth_vs; 319 | 320 | % find which layer it's in and find the product of Priors: 321 | 322 | layer = num_layers; 323 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 324 | 325 | for j = 1:num_layers - 1 326 | if nuclei_depths_prop(npt+num_layers+1) <= priors.layer_depths(j) 327 | layer = j; 328 | Prod_delta_prior = (priors.vsmax(j)-priors.vsmin(j) ); 329 | break 330 | end 331 | end 332 | 333 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(num_layers+npt+1) - nuclei_vs(ind) )^2/(2*sigma_birth_vs^2)); 334 | 335 | elseif (u<0.666) % DEATH +++++++++++++++++++++++++++++++++++++++++ 336 | death=1; 337 | if (s>burn_in) 338 | PD=PD+1; 339 | end 340 | 341 | npt_prop = npt-1; 342 | % choose a floating nuclei to remove 343 | ind=ceil(rand*npt)+num_layers; 344 | 345 | nuclei_depths_prop(1:num_layers+npt-1) = [nuclei_depths(1:ind-1) ; nuclei_depths(ind+1:num_layers+npt)]; 346 | nuclei_density_prop(1:num_layers + npt-1)= [nuclei_density(1:ind-1) ; nuclei_density(ind+1:num_layers+npt)]; 347 | nuclei_vs_prop(1:num_layers + npt-1)= [nuclei_vs(1:ind-1) ; nuclei_vs(ind+1:num_layers+npt)]; 348 | nuclei_vp_prop(1:num_layers + npt-1)= [nuclei_vp(1:ind-1) ; nuclei_vp(ind+1:num_layers+npt)]; 349 | 350 | death_pt_density = nuclei_density(ind); 351 | death_pt_vs = nuclei_vs(ind); 352 | death_pt_vp = nuclei_vp(ind); 353 | death_pt_depth = nuclei_depths(ind); 354 | 355 | 356 | %GET prob 357 | node=whichnuclei(nuclei_depths_prop(1:npt_prop+num_layers),death_pt_depth, num_layers,priors); 358 | %prob=(1/(sigmav*sqrt(2*pi)))*exp(-(pt(ind,2)-pt_prop(node,2))^2/(2*sigmav^2)); 359 | 360 | % find which layer it's in and find the product of Priors: 361 | layer = num_layers; 362 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 363 | for j = 1:num_layers - 1 364 | if death_pt_depth <= priors.layer_depths(j) 365 | layer = j; 366 | Prod_delta_prior = priors.vsmax(j)-priors.vsmin(j) ; 367 | break 368 | end 369 | end 370 | 371 | % the case of npt_prop = -1 is a rather special case but it results in an error. 372 | % when num_layers = 1. It is never excepted. 373 | if npt_prop == -1 374 | prob = 1; %set to anything. 375 | else 376 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(node) - death_pt_vs )^2/(2*sigma_birth_vs^2)); 377 | end 378 | 379 | 380 | 381 | else % MOVE +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 382 | if (s>burn_in) 383 | PP=PP+1; 384 | end 385 | move=1; 386 | npt_prop = npt; 387 | % choose the nuclei to move 388 | ind=ceil(rand*(npt+num_layers)); 389 | 390 | if num_layers == 1 || ind > num_layers %if ind is a 'floating' nuclei or depth constraints are not applied, move nuclei randomly using sigma_move_depth 391 | nuclei_depths_prop(ind) = nuclei_depths(ind)+randn*sigma_move_depth; 392 | else %if ind is a 'confined' nuclei, move nuclei randomly within the range of the layer depths 393 | if ind == 1 394 | top_of_layer = priors.depth_min; 395 | bottom_of_layer = priors.layer_depths(1); 396 | elseif ind < num_layers 397 | top_of_layer = priors.layer_depths(ind-1); 398 | bottom_of_layer = priors.layer_depths(ind); 399 | else 400 | top_of_layer = priors.layer_depths(ind-1); 401 | bottom_of_layer = priors.depth_max; 402 | end 403 | nuclei_depths_prop(ind) = (bottom_of_layer-top_of_layer).*rand(1) + top_of_layer; 404 | end 405 | 406 | % Find move probability 407 | 408 | % find which layer the nuclei is currently in: 409 | layer = num_layers; 410 | move_prob1 = priors.vsmax(layer)-priors.vsmin(layer); 411 | for j = 1:num_layers - 1 412 | if nuclei_depths(ind) <= priors.layer_depths(j) 413 | layer = j; 414 | move_prob1 = priors.vsmax(j)-priors.vsmin(j) ; 415 | break 416 | end 417 | end 418 | 419 | % find which layer the nuclei will move to: 420 | layer = num_layers; 421 | move_prob2 = priors.vsmax(layer)-priors.vsmin(layer); 422 | for j = 1:num_layers - 1 423 | if nuclei_depths_prop(ind) <= priors.layer_depths(j) 424 | layer = j; 425 | move_prob2 = priors.vsmax(j)-priors.vsmin(j) ; 426 | break 427 | end 428 | end 429 | move_prob = move_prob1 / move_prob2; 430 | 431 | end 432 | 433 | end % Change the position 434 | %---------------------------------------------------------------------- 435 | 436 | 437 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 438 | % COMPUTE MISFIT OF THE PROPOSED MODEL 439 | % If the proposed model is not outside the bounds of the uniform prior, 440 | % compute its misfit : "like_prop" 441 | if out==1 442 | like_prop=0; 443 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths_prop, nuclei_density_prop, nuclei_vp_prop, nuclei_vs_prop, npt_prop, num_layers, priors); 444 | 445 | if priors_OK == 0 446 | out = 0; 447 | like_prop = 0; 448 | else 449 | 450 | if running_mode == 1 451 | forward_model = [freq zeros(length(data),5)]; 452 | try 453 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 454 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 455 | catch 456 | errors_gpdc(s+1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [s, thickness, vp.', vs.', (density*1000).']; 457 | end %end 458 | 459 | %%%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 460 | min_misfit_all_modes = NaN(length(freq),1); 461 | 462 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 463 | 464 | misfit_fm = abs(data(i) - forward_model(i,2)); 465 | misfit_m1 = abs(data(i) - forward_model(i,3)); 466 | misfit_m2 = abs(data(i) - forward_model(i,4)); 467 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 468 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 469 | if i == 17 %set first freq picked to the fundamental mode 470 | misfit_all_modes = [misfit_fm]; 471 | else 472 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 473 | end 474 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 475 | end 476 | %end 477 | like_prop = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 478 | else 479 | like_prop = 1; 480 | end 481 | end 482 | 483 | end %if (out==1) 484 | 485 | 486 | 487 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 488 | %%% SEE WHETHER MODEL IS ACCEPTED 489 | 490 | accept=0; 491 | % This avoids runtime errors, as if out=0 Matlab insists on evaluating 492 | % Prod_delta_prior even though it never affects the calculation if out==0 493 | % (for the result is always 0). 494 | 495 | if out == 0 496 | Prod_delta_prior = 1; 497 | prob = 1; 498 | end 499 | 500 | % THe acceptance term takes different 501 | % values according the the proposal that has been made. 502 | 503 | if (birth==1) 504 | if (rand<((1/(Prod_delta_prior*prob))*exp(log(out)-like_prop+like))) 505 | accept=1; 506 | if (s>burn_in) 507 | AB=AB+1; 508 | end 509 | end 510 | elseif (death==1) 511 | 512 | if (rand<(Prod_delta_prior*prob*exp(log(out)-like_prop+like))) 513 | accept=1; 514 | if (s>burn_in) 515 | AD=AD+1; 516 | end 517 | end 518 | 519 | elseif (move == 1) % NO JUMP, i.e no change in dimension 520 | 521 | if (rand<(move_prob * exp(log(out)-like_prop+like))) 522 | accept=1; 523 | if (s>burn_in) 524 | AP=AP+1; 525 | end %if (s>burn_in) 526 | end 527 | 528 | else %change v_s 529 | if (randburn_in) 532 | AcV=AcV+1; 533 | end %if (s>burn_in) 534 | end 535 | end 536 | 537 | % If accept, update the values 538 | if (accept==1) 539 | npt=npt_prop; 540 | nuclei_depths = nuclei_depths_prop; 541 | nuclei_density = nuclei_density_prop; 542 | nuclei_vs = nuclei_vs_prop; 543 | nuclei_vp = nuclei_vp_prop; 544 | like=like_prop; 545 | end 546 | for i=1:dis 547 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),x(i),num_layers,priors); 548 | hist_vs(i)=nuclei_vs(ind); 549 | end 550 | [N]=histcounts2(x,hist_vs',x,y); 551 | vs_edge=y(1:(dis-1)); 552 | depth_edge=x(1:(dis-1)); 553 | 554 | 555 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 556 | % We collect the samples for the ensemble solution 557 | 558 | if (s>burn_in) 559 | if (mod(s,thin)==0) 560 | b=b+1; 561 | % DO THE AVERAGE 562 | 563 | for i=1:dis 564 | ind=whichnuclei(nuclei_depths,x(i), num_layers,priors); 565 | 566 | AV(i,1)=AV(i,1)+nuclei_vs(ind); 567 | 568 | % Do the 95% credible interval for vs 569 | if (b<=num) 570 | MINI_vs(i,b)=nuclei_vs(ind); 571 | MAXI_vs(i,b)=nuclei_vs(ind); 572 | if (b==num) 573 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 574 | [val_max_vs(i) ind_max_vs(i)]=max(MINI_vs(i,:)); 575 | end 576 | 577 | else 578 | if (nuclei_vs(ind)>val_min_vs(i)) 579 | MAXI_vs(i,ind_min_vs(i))=nuclei_vs(ind); 580 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 581 | end 582 | if (nuclei_vs(ind) find posterior; 0 -> Find priors. 36 | 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | % VERY IMPORTANT PARAMETERS 39 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%th 40 | 41 | burn_in=10000; % burn-in period 42 | nsample=1000000; % total number of samples 43 | 44 | %Uniform prior on depths for nuclei 45 | priors.depth_min=0; % Cannot be changed, always from the surface. 46 | priors.depth_max=40; 47 | priors.npt_max = 30; 48 | priors.npt_min = 0; 49 | 50 | num_layers = 3; 51 | 52 | priors.layer_depths = zeros(num_layers-1,1); %the last layer depth is infinity (and is not defined). 53 | priors.vsmin = zeros(num_layers,1); 54 | priors.vsmax = zeros(num_layers,1); 55 | priors.vp = zeros(num_layers,1); 56 | priors.density = zeros(num_layers,1); 57 | 58 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | % Define the priors and layer geometry 60 | if num_layers == 3 61 | priors.layer_depths(1) = 2 ; % snow depth. 62 | priors.layer_depths(2) = 25.5 ; % ice depth. 63 | priors.vsmin(1) = 500; % Snow 64 | priors.vsmax(1) = 1700; 65 | priors.vsmin(2) = 1700; % Ice 66 | priors.vsmax(2) = 1950; 67 | priors.vsmin(3) = 200; % rock 68 | priors.vsmax(3) = 2800; 69 | priors.vp(1) = 2500; % snow fixed vp 70 | priors.vp(2) = 3810; % ice fixed Vp 71 | priors.vp(3) = 4000; % rock fixed Vp 72 | priors.density(1) = 0.47; % snow fixed density 73 | priors.density(2) = 0.92; % ice fixed density 74 | priors.density(3) = 2.5; % rock fixed density 75 | elseif num_layers == 2 76 | priors.layer_depths(1) = 2 ; % snow depth. 77 | priors.vsmin(1) = 500; % Snow 78 | priors.vsmax(1) = 1700; 79 | priors.vsmin(2) = 200; % rock 80 | priors.vsmax(2) = 2800; 81 | priors.vp(1) = 2500; % snow fixed vp 82 | priors.vp(2) = 4000; % rock fixed Vp 83 | priors.density(1) = 0.47; % snow fixed density 84 | priors.density(2) = 2.5; % rock fixed density 85 | else % num_layers = 1 86 | priors.vsmin(1) = 200; % wide range of constraints 87 | priors.vsmax(1) = 2800; 88 | priors.vp(1) = 3500; % fixed vp 89 | priors.density(1) = 2; % fixed density 90 | end 91 | 92 | npt_init=1; % initial number of floating nuclei 93 | 94 | sigma_change_vs=20; % std deviation of Gaussian proposal on Change vs value 95 | sigma_move_depth = 1; % std deviation of Gaussian proposal on MOVE (change depth) 96 | sigma_birth_vs = 400; % std deviation of Gaussian proposal on BIRTH 97 | % (this number is also present in the DEATH 98 | % acceptance term when taking in acount the reverse jump ) 99 | 100 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101 | % LESS IMPORTANT PARAMETERS 102 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 103 | 104 | rng('default'); 105 | rng(4); 106 | % You can change the 1 to any other number to change the seed. 107 | 108 | % Define the limits of your model 109 | x_min = priors.depth_min; 110 | x_max = priors.depth_max; 111 | dis=80; % steps to discretize the model. Trade-off between computational time and accuracy. 112 | 113 | show=10000; % show statistics of the chain every "show" samples 114 | thin = 100; % thining 115 | 116 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117 | x =linspace(x_min,x_max,dis); % discretize the model 118 | y = linspace(min(priors.vsmin), max(priors.vsmax), dis); %y limits are Vs priors limits 119 | num=ceil((nsample-burn_in)*0.025/thin); % number of collected samples 120 | 121 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 122 | % Preallocation of variables 123 | 124 | b=0; 125 | bb=0; 126 | AV=zeros(dis,1); 127 | 128 | AB=0; 129 | AD=0; 130 | PB=0; 131 | PD=0; 132 | 133 | AcV=0; 134 | PV=0; 135 | AP=0; 136 | PP=0; 137 | 138 | errors_gpdc = nan(nsample,(1 + (priors.npt_max+num_layers)*4)); 139 | best=zeros(dis,1); 140 | val_min=zeros(dis,1); 141 | val_max=zeros(dis,1); 142 | ind_min_vs=zeros(dis,1); 143 | ind_max_vs=zeros(dis,1); 144 | hist_vs=zeros(dis,1); 145 | hist_density=zeros(dis,1); 146 | hierhist=zeros(nsample,1); 147 | change_points=zeros(nsample*(priors.npt_max+num_layers),1); 148 | cov=zeros(nsample,1); 149 | nnuclei=zeros(nsample,1); 150 | sup=zeros(dis,1); 151 | inf=zeros(dis,1); 152 | MINI_vs=zeros(dis,num); 153 | MAXI_vs=zeros(dis,num); 154 | CI_density=zeros((dis-1),(dis-1)); 155 | 156 | nnucleihist=zeros(priors.npt_max+num_layers,1); 157 | nuclei_depths=zeros(priors.npt_max+num_layers,1); 158 | nuclei_vs = zeros(priors.npt_max+num_layers,1); 159 | nuclei_vp = zeros(priors.npt_max+num_layers,1); 160 | nuclei_density = zeros(priors.npt_max+num_layers,1); 161 | thickness = zeros(priors.npt_max+num_layers,1); 162 | density = zeros(priors.npt_max+num_layers,1); 163 | vs = zeros(priors.npt_max+num_layers,1); 164 | vp = zeros(priors.npt_max+num_layers,1); 165 | 166 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167 | % Initialize - Define randomly the first model of the chain. Make sure 168 | % that it satisfies the priors. 169 | 170 | npt=npt_init; 171 | 172 | for i=1:npt+num_layers 173 | % define the layer depth. The first num_layer nuclei are special: the ith 174 | % nuclei must reside in the ith layer. 175 | 176 | if i <= num_layers 177 | if i == 1 178 | top_of_layer = priors.depth_min; 179 | if num_layers > 1 180 | bottom_of_layer = priors.layer_depths(1); 181 | else 182 | bottom_of_layer = priors.depth_max; 183 | end 184 | 185 | elseif i < num_layers 186 | top_of_layer = priors.layer_depths(i-1); 187 | bottom_of_layer = priors.layer_depths(i); 188 | else 189 | top_of_layer = priors.layer_depths(i-1); 190 | bottom_of_layer = priors.depth_max; 191 | end 192 | 193 | nuclei_depths(i)= (bottom_of_layer + top_of_layer) / 2; % fix nuclei to be in middle of layer 194 | else 195 | nuclei_depths(i)=priors.depth_min+rand*(priors.depth_max-priors.depth_min); % position of floating nuclei 196 | end 197 | 198 | % For each nuclei, find out which layer it is in: 199 | layer = num_layers; 200 | for j = 1:num_layers - 1 201 | if nuclei_depths(i) <= priors.layer_depths(j) 202 | layer = j; 203 | break 204 | end 205 | end 206 | 207 | % the variable 'layer' is the layer of the nuclei: 208 | nuclei_vs(i)=priors.vsmin(layer)+rand*(priors.vsmax(layer)-priors.vsmin(layer)); % vs 209 | nuclei_density(i)=priors.density(layer); 210 | nuclei_vp(i)=priors.vp(layer); 211 | 212 | end 213 | 214 | 215 | 216 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 217 | % COMPUTE INITIAL MISFIT 218 | % (Here, 'like' is the misfit ) 219 | like=0; 220 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths, nuclei_density, nuclei_vp, nuclei_vs, npt, num_layers, priors); 221 | 222 | %thickness(npt) = []; %remove last thickness for mat_disperse. 223 | if running_mode == 1 224 | forward_model = [freq zeros(length(data),5)]; 225 | try 226 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 227 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 228 | catch %creating error file to save varibles which do not run through the gpdc code called errors_gpdc 229 | errors_gpdc(1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [0, thickness, vp.', vs.', (density*1000).']; 230 | end %end 231 | 232 | %%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 233 | min_misfit_all_modes = NaN(length(freq),1); 234 | 235 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 236 | misfit_fm = abs(data(i) - forward_model(i,2)); 237 | misfit_m1 = abs(data(i) - forward_model(i,3)); 238 | misfit_m2 = abs(data(i) - forward_model(i,4)); 239 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 240 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 241 | if i == 17 %set first freq picked to the fundamental mode 242 | misfit_all_modes = [misfit_fm]; 243 | else 244 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 245 | end 246 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 247 | 248 | end %end multimodal misfit 249 | 250 | like = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 251 | else 252 | like = 1; 253 | end 254 | 255 | like_best=1e99; 256 | like_init=like; 257 | 258 | 259 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 260 | 261 | %%%%%%%%%%%%%%%%%% START RJ-MCMC SAMPLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 262 | 263 | fprintf('Total number of samples %i\n',nsample); 264 | fprintf('Acceptance rates:\n'); 265 | fprintf('Iteration Change Vs Move Depth Birth Death\n'); 266 | for s=1:nsample 267 | out=1; 268 | % Print statistics of the chain, The best is to "tune" these 269 | % ratios to 44 %. (Rosental 2000). 270 | if (mod(s,show)==0) 271 | number_of_samples = s; 272 | number_of_nuclei = npt; 273 | if (s>burn_in) 274 | fprintf('%7i %5.2f %5.2f %5.2f %5.2f\n',s, 100*AcV/PV, 100*AP/PP, 100*AB/PB,100*AD/PD); 275 | end 276 | end 277 | 278 | 279 | birth=0; 280 | move=0; 281 | death=0; 282 | 283 | nuclei_vs_prop=nuclei_vs; 284 | nuclei_vp_prop = nuclei_vp; 285 | nuclei_density_prop = nuclei_density; 286 | nuclei_depths_prop = nuclei_depths; 287 | 288 | like_prop = like; 289 | %---------------------------------------------------------------------- 290 | % Every even iteration, propose a new changed parameter value 291 | if (mod(s,2)==0) % Change Value 292 | if (s>burn_in) 293 | PV=PV+1; 294 | end 295 | npt_prop = npt; 296 | ind=ceil(rand*(npt+num_layers)); 297 | nuclei_vs_prop(ind) = nuclei_vs(ind) + randn * sigma_change_vs; 298 | 299 | %----------------------------------------------------------------------- 300 | % Every odd iteration change the nuclei tesselation 301 | else % Change position 302 | 303 | %u=1; % turning off birth/death 304 | u=rand; % Chose randomly between 3 different types of moves 305 | if (u<0.333) % BIRTH ++++++++++++++++++++++++++++++++++++++ 306 | birth=1; 307 | if (s>burn_in) 308 | PB=PB+1; 309 | end 310 | npt_prop = npt+1; 311 | nuclei_depths_prop(1:npt+num_layers) = nuclei_depths(1:npt+num_layers); 312 | nuclei_depths_prop(npt+num_layers+1) = priors.depth_min+rand*(priors.depth_max-priors.depth_min); 313 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),nuclei_depths_prop(npt+num_layers+1), num_layers, priors); 314 | 315 | 316 | nuclei_density_prop(npt+num_layers+1)=nuclei_density(ind); 317 | nuclei_vp_prop(npt+num_layers+1)=nuclei_vp(ind); 318 | nuclei_vs_prop(npt+num_layers+1)=nuclei_vs(ind)+randn*sigma_birth_vs; 319 | 320 | % find which layer it's in and find the product of Priors: 321 | 322 | layer = num_layers; 323 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 324 | 325 | for j = 1:num_layers - 1 326 | if nuclei_depths_prop(npt+num_layers+1) <= priors.layer_depths(j) 327 | layer = j; 328 | Prod_delta_prior = (priors.vsmax(j)-priors.vsmin(j) ); 329 | break 330 | end 331 | end 332 | 333 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(num_layers+npt+1) - nuclei_vs(ind) )^2/(2*sigma_birth_vs^2)); 334 | 335 | elseif (u<0.666) % DEATH +++++++++++++++++++++++++++++++++++++++++ 336 | death=1; 337 | if (s>burn_in) 338 | PD=PD+1; 339 | end 340 | 341 | npt_prop = npt-1; 342 | % choose a floating nuclei to remove 343 | ind=ceil(rand*npt)+num_layers; 344 | 345 | nuclei_depths_prop(1:num_layers+npt-1) = [nuclei_depths(1:ind-1) ; nuclei_depths(ind+1:num_layers+npt)]; 346 | nuclei_density_prop(1:num_layers + npt-1)= [nuclei_density(1:ind-1) ; nuclei_density(ind+1:num_layers+npt)]; 347 | nuclei_vs_prop(1:num_layers + npt-1)= [nuclei_vs(1:ind-1) ; nuclei_vs(ind+1:num_layers+npt)]; 348 | nuclei_vp_prop(1:num_layers + npt-1)= [nuclei_vp(1:ind-1) ; nuclei_vp(ind+1:num_layers+npt)]; 349 | 350 | death_pt_density = nuclei_density(ind); 351 | death_pt_vs = nuclei_vs(ind); 352 | death_pt_vp = nuclei_vp(ind); 353 | death_pt_depth = nuclei_depths(ind); 354 | 355 | 356 | %GET prob 357 | node=whichnuclei(nuclei_depths_prop(1:npt_prop+num_layers),death_pt_depth, num_layers,priors); 358 | %prob=(1/(sigmav*sqrt(2*pi)))*exp(-(pt(ind,2)-pt_prop(node,2))^2/(2*sigmav^2)); 359 | 360 | % find which layer it's in and find the product of Priors: 361 | layer = num_layers; 362 | Prod_delta_prior = priors.vsmax(layer)-priors.vsmin(layer); 363 | for j = 1:num_layers - 1 364 | if death_pt_depth <= priors.layer_depths(j) 365 | layer = j; 366 | Prod_delta_prior = priors.vsmax(j)-priors.vsmin(j) ; 367 | break 368 | end 369 | end 370 | 371 | % the case of npt_prop = -1 is a rather special case but it results in an error. 372 | % when num_layers = 1. It is never excepted. 373 | if npt_prop == -1 374 | prob = 1; %set to anything. 375 | else 376 | prob = 1.0 / (sigma_birth_vs*sqrt(2*pi)) * exp(-( nuclei_vs_prop(node) - death_pt_vs )^2/(2*sigma_birth_vs^2)); 377 | end 378 | 379 | 380 | 381 | else % MOVE +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 382 | if (s>burn_in) 383 | PP=PP+1; 384 | end 385 | move=1; 386 | npt_prop = npt; 387 | % choose the nuclei to move 388 | ind=ceil(rand*(npt+num_layers)); 389 | 390 | if num_layers == 1 || ind > num_layers %if ind is a 'floating' nuclei or depth constraints are not applied, move nuclei randomly using sigma_move_depth 391 | nuclei_depths_prop(ind) = nuclei_depths(ind)+randn*sigma_move_depth; 392 | else %if ind is a 'confined' nuclei, move nuclei randomly within the range of the layer depths 393 | if ind == 1 394 | top_of_layer = priors.depth_min; 395 | bottom_of_layer = priors.layer_depths(1); 396 | elseif ind < num_layers 397 | top_of_layer = priors.layer_depths(ind-1); 398 | bottom_of_layer = priors.layer_depths(ind); 399 | else 400 | top_of_layer = priors.layer_depths(ind-1); 401 | bottom_of_layer = priors.depth_max; 402 | end 403 | nuclei_depths_prop(ind) = (bottom_of_layer-top_of_layer).*rand(1) + top_of_layer; 404 | end 405 | 406 | % Find move probability 407 | 408 | % find which layer the nuclei is currently in: 409 | layer = num_layers; 410 | move_prob1 = priors.vsmax(layer)-priors.vsmin(layer); 411 | for j = 1:num_layers - 1 412 | if nuclei_depths(ind) <= priors.layer_depths(j) 413 | layer = j; 414 | move_prob1 = priors.vsmax(j)-priors.vsmin(j) ; 415 | break 416 | end 417 | end 418 | 419 | % find which layer the nuclei will move to: 420 | layer = num_layers; 421 | move_prob2 = priors.vsmax(layer)-priors.vsmin(layer); 422 | for j = 1:num_layers - 1 423 | if nuclei_depths_prop(ind) <= priors.layer_depths(j) 424 | layer = j; 425 | move_prob2 = priors.vsmax(j)-priors.vsmin(j) ; 426 | break 427 | end 428 | end 429 | move_prob = move_prob1 / move_prob2; 430 | 431 | end 432 | 433 | end % Change the position 434 | %---------------------------------------------------------------------- 435 | 436 | 437 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 438 | % COMPUTE MISFIT OF THE PROPOSED MODEL 439 | % If the proposed model is not outside the bounds of the uniform prior, 440 | % compute its misfit : "like_prop" 441 | if out==1 442 | like_prop=0; 443 | [thickness, density, vp, vs, priors_OK] = thicknesses_and_priors(nuclei_depths_prop, nuclei_density_prop, nuclei_vp_prop, nuclei_vs_prop, npt_prop, num_layers, priors); 444 | 445 | if priors_OK == 0 446 | out = 0; 447 | like_prop = 0; 448 | else 449 | 450 | if running_mode == 1 451 | forward_model = [freq zeros(length(data),5)]; 452 | try 453 | forward_model = gpdc(thickness, vp.', vs.', (density*1000).', 'fV', freq.'); 454 | forward_model = [forward_model(:, 1), rdivide(1, forward_model(:, 2:end))]; %convert forward model into velocity (m/s) 455 | catch 456 | errors_gpdc(s+1,1:(1+length(thickness)+length(vp.')+length(vs.')+length((density*1000).'))) = [s, thickness, vp.', vs.', (density*1000).']; 457 | end %end 458 | 459 | %%%%%%%%%%% computing multimodal misfit %%%%%%%%%%% 460 | min_misfit_all_modes = NaN(length(freq),1); 461 | 462 | for i = 1:length(freq) % frequency samples, this should match the frequency samples. 463 | 464 | misfit_fm = abs(data(i) - forward_model(i,2)); 465 | misfit_m1 = abs(data(i) - forward_model(i,3)); 466 | misfit_m2 = abs(data(i) - forward_model(i,4)); 467 | %misfit_m3 = abs(data(i) - forward_model(i,5)); 468 | %misfit_m4 = abs(data(i) - forward_model(i,6)); 469 | if i == 17 %set first freq picked to the fundamental mode 470 | misfit_all_modes = [misfit_fm]; 471 | else 472 | misfit_all_modes = [misfit_fm misfit_m1 misfit_m2]; 473 | end 474 | min_misfit_all_modes(i,1) = min(misfit_all_modes); 475 | end 476 | %end 477 | like_prop = nansum( (min_misfit_all_modes).^2 ./(2 * fitting_error.^2) ); 478 | else 479 | like_prop = 1; 480 | end 481 | end 482 | 483 | end %if (out==1) 484 | 485 | 486 | 487 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 488 | %%% SEE WHETHER MODEL IS ACCEPTED 489 | 490 | accept=0; 491 | % This avoids runtime errors, as if out=0 Matlab insists on evaluating 492 | % Prod_delta_prior even though it never affects the calculation if out==0 493 | % (for the result is always 0). 494 | 495 | if out == 0 496 | Prod_delta_prior = 1; 497 | prob = 1; 498 | end 499 | 500 | % THe acceptance term takes different 501 | % values according the the proposal that has been made. 502 | 503 | if (birth==1) 504 | if (rand<((1/(Prod_delta_prior*prob))*exp(log(out)-like_prop+like))) 505 | accept=1; 506 | if (s>burn_in) 507 | AB=AB+1; 508 | end 509 | end 510 | elseif (death==1) 511 | 512 | if (rand<(Prod_delta_prior*prob*exp(log(out)-like_prop+like))) 513 | accept=1; 514 | if (s>burn_in) 515 | AD=AD+1; 516 | end 517 | end 518 | 519 | elseif (move == 1) % NO JUMP, i.e no change in dimension 520 | 521 | if (rand<(move_prob * exp(log(out)-like_prop+like))) 522 | accept=1; 523 | if (s>burn_in) 524 | AP=AP+1; 525 | end %if (s>burn_in) 526 | end 527 | 528 | else %change v_s 529 | if (randburn_in) 532 | AcV=AcV+1; 533 | end %if (s>burn_in) 534 | end 535 | end 536 | 537 | % If accept, update the values 538 | if (accept==1) 539 | npt=npt_prop; 540 | nuclei_depths = nuclei_depths_prop; 541 | nuclei_density = nuclei_density_prop; 542 | nuclei_vs = nuclei_vs_prop; 543 | nuclei_vp = nuclei_vp_prop; 544 | like=like_prop; 545 | end 546 | for i=1:dis 547 | ind=whichnuclei(nuclei_depths(1:npt+num_layers),x(i),num_layers,priors); 548 | hist_vs(i)=nuclei_vs(ind); 549 | end 550 | [N]=histcounts2(x,hist_vs',x,y); 551 | vs_edge=y(1:(dis-1)); 552 | depth_edge=x(1:(dis-1)); 553 | 554 | 555 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 556 | % We collect the samples for the ensemble solution 557 | 558 | if (s>burn_in) 559 | if (mod(s,thin)==0) 560 | b=b+1; 561 | % DO THE AVERAGE 562 | 563 | for i=1:dis 564 | ind=whichnuclei(nuclei_depths,x(i), num_layers,priors); 565 | 566 | AV(i,1)=AV(i,1)+nuclei_vs(ind); 567 | 568 | % Do the 95% credible interval for vs 569 | if (b<=num) 570 | MINI_vs(i,b)=nuclei_vs(ind); 571 | MAXI_vs(i,b)=nuclei_vs(ind); 572 | if (b==num) 573 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 574 | [val_max_vs(i) ind_max_vs(i)]=max(MINI_vs(i,:)); 575 | end 576 | 577 | else 578 | if (nuclei_vs(ind)>val_min_vs(i)) 579 | MAXI_vs(i,ind_min_vs(i))=nuclei_vs(ind); 580 | [val_min_vs(i) ind_min_vs(i)]=min(MAXI_vs(i,:)); 581 | end 582 | if (nuclei_vs(ind) priors.npt_max | num_floating_nuclei < priors.npt_min 14 | priors_OK = 0; thickness = 0; layer_density = 0; layer_vp = 0; layer_vs = 0; %early return 15 | return; 16 | end 17 | 18 | % checking the special domain-confined (unsorted) nuclei 19 | if num_layers > 1 % dont check if num_layers = 1 20 | for i = 1:num_layers 21 | if i == 1 22 | top_of_layer = priors.depth_min; 23 | bottom_of_layer = priors.layer_depths(1); 24 | elseif i < num_layers 25 | top_of_layer = priors.layer_depths(i-1); 26 | bottom_of_layer = priors.layer_depths(i); 27 | else 28 | top_of_layer = priors.layer_depths(i-1); 29 | bottom_of_layer = priors.depth_max; 30 | end 31 | if nuclei_positions_unsorted(i) < top_of_layer | nuclei_positions_unsorted(i) > bottom_of_layer 32 | priors_OK = 0; thickness = 0; layer_density = 0; layer_vp = 0; layer_vs = 0; %early return 33 | return; 34 | end 35 | end 36 | end 37 | 38 | [nuclei_positions,I] = sort(nuclei_positions_unsorted(1:num_floating_nuclei+num_layers)); 39 | 40 | % define the variables. Note that since everything is sorted by 41 | % depth, we can do this in one pass: 42 | 43 | layer_vs = [nuclei_vs(I) ]; 44 | layer_vp = [nuclei_vp(I) ]; 45 | layer_density = [nuclei_density(I) ]; 46 | 47 | % Test priors on vs 48 | for i=1: num_floating_nuclei + num_layers 49 | 50 | % Find the layer of the ith nuclei 51 | layer = num_layers; 52 | for j = 1:num_layers - 1 53 | if nuclei_positions(i) <= priors.layer_depths(j) 54 | layer = j; 55 | break; 56 | end 57 | end 58 | % Test the prior 59 | if layer_vs(i) < priors.vsmin(layer) || layer_vs(i) > priors.vsmax(layer) 60 | priors_OK = 0; 61 | return; % early return 62 | end 63 | end 64 | 65 | if( max( nuclei_positions ) > priors.depth_max | min( nuclei_positions ) < priors.depth_min ) 66 | priors_OK = 0; 67 | return; 68 | end 69 | 70 | % Assemble the layer thicknesses, taking note also of the fixed domain 71 | % boundaries. 72 | 73 | starting_index = 1; 74 | 75 | for layer = 1:num_layers 76 | if num_layers ==1 77 | layer_indices = 1:num_floating_nuclei+num_layers; 78 | top_of_layer = 0 ; 79 | else 80 | if layer == 1 81 | layer_indices = find( nuclei_positions < priors.layer_depths(layer)); 82 | top_of_layer = 0; 83 | elseif layer < num_layers 84 | layer_indices = find( nuclei_positions < priors.layer_depths(layer) & nuclei_positions > priors.layer_depths(layer-1)); 85 | top_of_layer = priors.layer_depths(layer-1); 86 | else 87 | layer_indices = find(nuclei_positions > priors.layer_depths(layer-1)); 88 | top_of_layer = priors.layer_depths(layer-1); 89 | end 90 | end 91 | 92 | if numel(layer_indices) == 1 %If there is only one point in the domain, then.... 93 | if layer == 1 94 | if num_layers == 1 95 | thickness(starting_index) = 0; %one point, and one layer... 96 | else 97 | thickness(starting_index) = priors.layer_depths(1); 98 | end 99 | elseif layer < num_layers 100 | thickness(starting_index) = priors.layer_depths(layer) - priors.layer_depths(layer-1); 101 | else 102 | thickness(starting_index) = 0; %set last thickness to 0 -- it represents the half space. 103 | end 104 | 105 | else %more than one nuclei within the layer. 106 | thickness(starting_index) = 0.5 * (nuclei_positions(layer_indices(1)) + nuclei_positions(layer_indices(2))) - top_of_layer; 107 | % fill intermediate layers 108 | for i=2: numel(layer_indices)-1 109 | thickness(i+starting_index-1) = 0.5 * (nuclei_positions(layer_indices(i+1))+nuclei_positions(layer_indices(i))) - 0.5 * (nuclei_positions(layer_indices(i)) + nuclei_positions(layer_indices(i-1))); 110 | end 111 | % now do last internal layer 112 | if layer == num_layers 113 | thickness(starting_index-1 + numel(layer_indices)) = 0; %set last layer to have depth 0 114 | else 115 | thickness(starting_index-1 + numel(layer_indices)) = priors.layer_depths(layer) - sum( thickness(1:starting_index + numel(layer_indices)-1 )); 116 | end 117 | end 118 | starting_index = starting_index + numel(layer_indices); 119 | end 120 | 121 | 122 | 123 | end %end of function 124 | -------------------------------------------------------------------------------- /functions/thicknesses_and_priors_III.m: -------------------------------------------------------------------------------- 1 | function [thickness, layer_density, layer_vp, layer_vs, priors_OK] = ... 2 | thicknesses_and_priors_III(nuclei_positions_unsorted, nuclei_density, nuclei_vp, nuclei_vs, num_floating_nuclei, num_layers, priors) 3 | % Function layers_and_priors 4 | % (i) Tests prior information 5 | % (ii) If all priors OK, converts from Voronoi description to layer description 6 | 7 | % 8 | 9 | priors_OK = 1; % 1 means all OK, 0 means priors not satisfied, reject model 10 | thickness = zeros(1, num_floating_nuclei+num_layers); 11 | % 12 | 13 | if num_floating_nuclei > priors.npt_max | num_floating_nuclei < priors.npt_min 14 | priors_OK = 0; thickness = 0; layer_density = 0; layer_vp = 0; layer_vs = 0; %early return 15 | return; 16 | end 17 | 18 | % checking the special domain-confined (unsorted) nuclei 19 | if num_layers > 1 % dont check if num_layers = 1 20 | for i = 1:num_layers 21 | if i == 1 22 | top_of_layer = priors.depth_min; 23 | bottom_of_layer = priors.layer_depths(1); 24 | elseif i < num_layers 25 | top_of_layer = priors.layer_depths(i-1); 26 | bottom_of_layer = priors.layer_depths(i); 27 | else 28 | top_of_layer = priors.layer_depths(i-1); 29 | bottom_of_layer = priors.depth_max; 30 | end 31 | if nuclei_positions_unsorted(i) < top_of_layer | nuclei_positions_unsorted(i) > bottom_of_layer 32 | priors_OK = 0; thickness = 0; layer_density = 0; layer_vp = 0; layer_vs = 0; %early return 33 | return; 34 | end 35 | end 36 | end 37 | 38 | [nuclei_positions,I] = sort(nuclei_positions_unsorted(1:num_floating_nuclei+num_layers)); 39 | 40 | % define the variables. Note that since everything is sorted by 41 | % depth, we can do this in one pass: 42 | 43 | layer_vs = [nuclei_vs(I) ]; 44 | layer_vp = [nuclei_vp(I) ]; 45 | layer_density = [nuclei_density(I) ]; 46 | PR = 0.5*((((layer_vp./layer_vs).^2)-2)./(((layer_vp./layer_vs).^2)-1)); 47 | 48 | % Test priors on vs 49 | for i=1: num_floating_nuclei + num_layers 50 | 51 | % Find the layer of the ith nuclei 52 | layer = num_layers; 53 | for j = 1:num_layers - 1 54 | if nuclei_positions(i) <= priors.layer_depths(j) 55 | layer = j; 56 | break; 57 | end 58 | end 59 | % Test the prior 60 | if layer_vs(i) < priors.vsmin(layer) || layer_vs(i) > priors.vsmax(layer) %Vs bounds 61 | priors_OK = 0; 62 | return; % early return 63 | end 64 | if PR(i) < priors.PRmin(layer) || PR(i) > priors.PRmax(layer) %PR bounds 65 | priors_OK = 0; 66 | return; % early return 67 | end 68 | end 69 | 70 | if( max( nuclei_positions ) > priors.depth_max | min( nuclei_positions ) < priors.depth_min ) 71 | priors_OK = 0; 72 | return; 73 | end 74 | 75 | % Assemble the layer thicknesses, taking note also of the fixed domain 76 | % boundaries. 77 | 78 | starting_index = 1; 79 | 80 | for layer = 1:num_layers 81 | if num_layers ==1 82 | layer_indices = 1:num_floating_nuclei+num_layers; 83 | top_of_layer = 0 ; 84 | else 85 | if layer == 1 86 | layer_indices = find( nuclei_positions < priors.layer_depths(layer)); 87 | top_of_layer = 0; 88 | elseif layer < num_layers 89 | layer_indices = find( nuclei_positions < priors.layer_depths(layer) & nuclei_positions > priors.layer_depths(layer-1)); 90 | top_of_layer = priors.layer_depths(layer-1); 91 | else 92 | layer_indices = find(nuclei_positions > priors.layer_depths(layer-1)); 93 | top_of_layer = priors.layer_depths(layer-1); 94 | end 95 | end 96 | 97 | if numel(layer_indices) == 1 %If there is only one point in the domain, then.... 98 | if layer == 1 99 | if num_layers == 1 100 | thickness(starting_index) = 0; %one point, and one layer... 101 | else 102 | thickness(starting_index) = priors.layer_depths(1); 103 | end 104 | elseif layer < num_layers 105 | thickness(starting_index) = priors.layer_depths(layer) - priors.layer_depths(layer-1); 106 | else 107 | thickness(starting_index) = 0; %set last thickness to 0 -- it represents the half space. 108 | end 109 | 110 | else %more than one nuclei within the layer. 111 | thickness(starting_index) = 0.5 * (nuclei_positions(layer_indices(1)) + nuclei_positions(layer_indices(2))) - top_of_layer; 112 | % fill intermediate layers 113 | for i=2: numel(layer_indices)-1 114 | thickness(i+starting_index-1) = 0.5 * (nuclei_positions(layer_indices(i+1))+nuclei_positions(layer_indices(i))) - 0.5 * (nuclei_positions(layer_indices(i)) + nuclei_positions(layer_indices(i-1))); 115 | end 116 | % now do last internal layer 117 | if layer == num_layers 118 | thickness(starting_index-1 + numel(layer_indices)) = 0; %set last layer to have depth 0 119 | else 120 | thickness(starting_index-1 + numel(layer_indices)) = priors.layer_depths(layer) - sum( thickness(1:starting_index + numel(layer_indices)-1 )); 121 | end 122 | end 123 | starting_index = starting_index + numel(layer_indices); 124 | end 125 | 126 | 127 | 128 | end %end of function 129 | -------------------------------------------------------------------------------- /functions/whichnuclei.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % This is a function called by the main inversion program 3 | % that finds the nuclei index corresponding to the depth. 4 | % 5 | 6 | function index = whichnuclei(points, depth,num_layers, priors) 7 | 8 | %find out which domain the nuclei is in: 9 | layer = num_layers; 10 | for j = 1:num_layers - 1 11 | if depth <= priors.layer_depths(j) 12 | layer = j; 13 | break 14 | end 15 | end 16 | 17 | % Find the top/bottom of the layer 18 | if layer == 1 19 | if num_layers == 1 20 | top_of_layer = priors.depth_min; 21 | bottom_of_layer = priors.depth_max; 22 | else 23 | top_of_layer = priors.depth_min; 24 | bottom_of_layer = priors.layer_depths(1); 25 | end 26 | elseif layer < num_layers 27 | top_of_layer = priors.layer_depths(layer-1); 28 | bottom_of_layer = priors.layer_depths(layer); 29 | else 30 | top_of_layer = priors.layer_depths(layer-1); 31 | bottom_of_layer = priors.depth_max; 32 | end 33 | 34 | 35 | indices = find( (points < bottom_of_layer) & (points >= top_of_layer) ); 36 | 37 | [Y,index] = min(abs( depth - points(indices))); 38 | index = indices(index); 39 | 40 | end 41 | 42 | -------------------------------------------------------------------------------- /gpdc mex file LINUX/READ_ME.txt: -------------------------------------------------------------------------------- 1 | #--- gpdc 2 | 3 | A mex interface to the geopsy (http://geopsy.org/) software, to 4 | replicate the functionality of the gpdc program 5 | (http://www.geopsy.org/wiki/index.php/Gpdc). 6 | 7 | The Matlab mex interface replicates much of the geopsy source code found 8 | in the geopsy source file DispersionReader.cpp, but does not implement 9 | all features (e.g. Grid Mode is not implemented). The mex interface also 10 | adds the ability to specify frequency values, rather than just the 11 | minimum and maximum of the range. 12 | 13 | Some defaults differ from the gpdc defaults, and these are noted in the 14 | source code. 15 | 16 | #-- Usage: 17 | 18 | Usage examples: 19 | 20 | out = gpdc(T, Vp, Vs, d) 21 | out = gpdc(T, Vp, Vs, d, 'nSamples', n, 'minRange', mn, 'maxRange', mx) 22 | out = gpdc(T, Vp, Vs, d, 'fV', f) 23 | 24 | Where required input: 25 | 26 | T = Thickness(m) : double vector 27 | Vp = Vp (m/s) : double vector 28 | Vs = Vs (m/s) : double vector 29 | d = density (kg/m3) : double vector 30 | 31 | Optional input for frequency values. One or more of these options can be 32 | set: 33 | 34 | n = number of samples : scalar integer 35 | mn = minimum range : scalar double 36 | mx = maximum range : scalar double 37 | 38 | Alternatively, the frequency values can be set from a vector of doubles: 39 | 40 | f = frequency vector : double vector 41 | 42 | If 'fV' is provided 'nSamples', 'minRange' and 'maxRange' values will be 43 | ignored. 44 | 45 | Example using fV: 46 | 47 | out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 48 | 49 | Which should be equivalent to: 50 | 51 | gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 52 | 53 | #- Output: 54 | 55 | out = 2d matrix 56 | 57 | col1 : x values 58 | col2 : y values for mode 0 59 | col3 : y values for mode 1 60 | ... 61 | 62 | For example: 63 | 64 | T = [7.5, 25, 0]; 65 | Vp = [500, 1350, 2000]; 66 | Vs = [200, 210, 1000]; 67 | d = [1700, 1900, 2500]; 68 | out = gpdc(T, Vp, Vs, d); 69 | plot(out(:, 1), out(:, 2:end)) 70 | 71 | Which should be equivalent to (these command line options match our defaults): 72 | 73 | gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 74 | 75 | #-- Compiling: 76 | 77 | The mex interface has been mostly tested on CentOS 7, and Windows 7, 78 | with Matlab 2017a and geopsy 2.10.0. 79 | 80 | #- Linux: 81 | 82 | Presuming the Matlab bin directory is in the PATH, the geopsy software 83 | is installed at ${GEOPSY_HOME}, and we are using the system version of 84 | Qt, installed within the /usr directory, the mex file can be compiled 85 | with: 86 | 87 | mex gpdc.cpp \ 88 | -I/usr/include/QtCore \ 89 | -L${GEOPSY_HOME} \ 90 | -lQGpCoreTools \ 91 | -lQGpCoreWave \ 92 | LDFLAGS="-Wl,-rpath,${GEOPSY_HOME}/lib" 93 | 94 | Which should produce the file: 95 | 96 | gpdc.mexa64 97 | 98 | Testing has found that if the system version of Qt differs from the 99 | version of Qt used by Matlab, this can cause crashes when using the 100 | Matlab graphical interface. 101 | 102 | To avoid the crashes, the geopsy code and mex code can be compiled using 103 | the same version of Qt as used by Matlab. For example, Matlab 2017a uses 104 | Qt 5.5.1. The build process is a bit more complicated, but does not 105 | require building the entire geopsy suite, as only QGpCoreTools and 106 | QGpCoreWave are used. 107 | 108 | Notes on building Qt 5.5.1, required geopsy libraries, and mex interface 109 | for Matlab 2017a, where everything will be built and installed within 110 | the current working directory. Presumes Matlab is installed at 111 | ${MATLAB_HOME}: 112 | 113 | export CFLAGS='-O2 -fPIC' 114 | export CXXFLAGS='-O2 -fPIC' 115 | export FFLAGS='-O2 -fPIC' 116 | export FCFLAGS='-O2 -fPIC' 117 | 118 | unset QTDIR 119 | unset QTINC 120 | unset QTLIB 121 | 122 | #- Qt 5.5.1: 123 | 124 | wget "http://download.qt.io/archive/qt/5.5/5.5.1/single/qt-everywhere-opensource-src-5.5.1.tar.xz" 125 | tar xJf qt-everywhere-opensource-src-5.5.1.tar.xz 126 | 127 | mkdir build.qt-everywhere-opensource-src-5.5.1 128 | cd build.qt-everywhere-opensource-src-5.5.1 129 | 130 | mkdir ../qt5 131 | qt5Prefix="$(readlink -f ../qt5)" 132 | 133 | ../qt-everywhere-opensource-src-5.5.1/configure \ 134 | -opensource \ 135 | -confirm-license \ 136 | -no-rpath \ 137 | -qt-xcb \ 138 | -no-audio-backend \ 139 | -nomake examples \ 140 | -nomake tests \ 141 | -make libs \ 142 | -prefix ${qt5Prefix} \ 143 | -bindir ${qt5Prefix}/bin && \ 144 | LD_LIBRARY_PATH="$(pwd)/lib:${LD_LIBRARY_PATH}" \ 145 | make -j32 && \ 146 | LD_LIBRARY_PATH="$(pwd)/lib:${LD_LIBRARY_PATH}" \ 147 | make -j32 install && \ 148 | cd .. 149 | 150 | PATH="$(pwd)/qt5/bin:${PATH}" 151 | CPATH="$(pwd)/qt5/include:${CPATH}" 152 | LIBRARY_PATH="$(pwd)/qt5/lib:${LIBRARY_PATH}" 153 | LD_LIBRARY_PATH="$(pwd)/qt5/lib:${LIBRARY_PATH}" 154 | 155 | #- geopsy: 156 | # sources downloaded from: 157 | # http://www.geopsy.org/download.php 158 | 159 | tar xzf geopsypack-55items-src-2.10.1.tar.gz 160 | cd geopsypack-55items-src-2.10.1 161 | 162 | mkdir ../geopsy 163 | gpPrefix="$(readlink -f ../geopsy)" 164 | 165 | echo 'yes' | \ 166 | ./configure \ 167 | -prefix ${gpPrefix} \ 168 | -I ${qt5Prefix}/include \ 169 | -I ${qt5Prefix}/include/QtCore \ 170 | -L ${qt5Prefix}/lib \ 171 | -I ${MATLAB_HOME}/extern/include \ 172 | -L ${MATLAB_HOME}/bin/glnxa64 173 | 174 | # Only need to make QGpCoreTools and QGpCoreWave: 175 | 176 | cd QGpCoreTools 177 | 178 | # Patches for Qt 5.5.1: 179 | 180 | cp src/AbstractStream.h \ 181 | src/AbstractStream.h.original 182 | sed -i 's|fromAscii|fromLatin1|g' \ 183 | src/AbstractStream.h 184 | 185 | cp src/Cache.cpp \ 186 | src/Cache.cpp.original 187 | sed -i 's|toAscii|toLatin1|g' \ 188 | src/Cache.cpp 189 | 190 | cp src/ConsoleProgress.cpp \ 191 | src/ConsoleProgress.cpp.original 192 | sed -i 's|toAscii|toLatin1|g' \ 193 | src/ConsoleProgress.cpp 194 | 195 | cp src/CoreApplicationPrivate.cpp \ 196 | src/CoreApplicationPrivate.cpp.original 197 | sed -i 's|toAscii|toLatin1|g' \ 198 | src/CoreApplicationPrivate.cpp 199 | sed -i '/qInstallMsgHandler/d' \ 200 | src/CoreApplicationPrivate.cpp 201 | 202 | cp src/XMLClass.cpp \ 203 | src/XMLClass.cpp.original 204 | sed -i 's|toAscii|toLatin1|g' \ 205 | src/XMLClass.cpp 206 | 207 | cp src/Tar.cpp \ 208 | src/Tar.cpp.original 209 | sed -i 's|toAscii|toLatin1|g' \ 210 | src/Tar.cpp 211 | 212 | cp src/XMLParser.cpp \ 213 | src/XMLParser.cpp.original 214 | sed -i 's|toAscii|toLatin1|g' \ 215 | src/XMLParser.cpp 216 | 217 | cp src/Thread.cpp \ 218 | src/Thread.cpp.original 219 | sed -i '/QThread::finished()/d' \ 220 | src/Thread.cpp 221 | 222 | make -j16 release 223 | make -j16 release-install 224 | cd .. 225 | 226 | \cp include/QGpCoreTools/QGpCoreToolsInstallPath.h \ 227 | ${gpPrefix}/include/ 228 | 229 | cd QGpCoreWave 230 | 231 | make -j16 release 232 | make -j16 release-install 233 | cd .. 234 | 235 | \cp include/QGpCoreWave/QGpCoreWaveInstallPath.h \ 236 | ${gpPrefix}/include/ 237 | 238 | cd .. 239 | 240 | #- mex file - presume mex source is already in 'mex' directory ... : 241 | 242 | cd mex 243 | 244 | g++ \ 245 | gpdc.cpp \ 246 | -O2 \ 247 | -fPIC \ 248 | -fpermissive \ 249 | -shared \ 250 | -DMATLAB_MEX_FILE \ 251 | -o gpdc.mexa64 \ 252 | -I${gpPrefix}/include \ 253 | -I${qt5Prefix}/include \ 254 | -I${qt5Prefix}/include/QtCore \ 255 | -I${MATLAB_HOME}/extern/include \ 256 | -L${MATLAB_HOME}/bin/glnxa64 \ 257 | -lmex \ 258 | -lmx \ 259 | -leng \ 260 | -lmat \ 261 | -L${qt5Prefix}/lib \ 262 | -lQt5Core \ 263 | -L${gpPrefix}/lib \ 264 | -lQGpCoreTools \ 265 | -lQGpCoreWave 266 | 267 | This will build the file gpdc.mexa64, which will require the libraries 268 | ${gpPrefix}/libQGpCoreTools.so.1 and ${gpPrefix}/libQGpCoreWave.so.1 to 269 | run. 270 | 271 | For the end user, using the patchelf (https://nixos.org/patchelf.html) 272 | program to set the appropriate RPATH for these files is recommended. 273 | 274 | For example, if the mex file was to be installed at and run from the 275 | directory ${HOME}/matlab/gpc, the required files can be copied in to 276 | place: 277 | 278 | ${HOME}/matlab/gpdc/ 279 | ├── gpdc.mexa64 280 | └── lib/ 281 | ├── libQGpCoreTools.so.1 282 | └── libQGpCoreWave.so.1 283 | 284 | The following patchelf commands can then be used to set appropriate 285 | RPATH values for the files: 286 | 287 | patchelf --remove-rpath ${HOME}/matlab/gpdc/gpdc.mexa64 288 | patchelf --remove-rpath ${HOME}/matlab/gpdc/lib/libQGpCoreTools.so.1 289 | patchelf --remove-rpath ${HOME}/matlab/gpdc/lib/libQGpCoreWave.so.1 290 | patchelf \ 291 | --set-rpath \ 292 | ${MATLAB_HOME}/sys/os/glnxa64:${MATLAB_HOME}/bin/glnxa64:${HOME}/matlab/gpdc/lib \ 293 | gpdc.mexa64 294 | 295 | The directory ${HOME}/matlab/gpdc can then be added to the Matlab path 296 | using the preferred method. 297 | 298 | #- Windows: 299 | 300 | People who are more used to doing this kind of thing in Windows may know 301 | better ways of doing this ... 302 | 303 | Building on Windows (Windows 7 / Matlab 2017a) was done within a Git 304 | Bash shell (https://git-scm.com/download/win). 305 | 306 | TDM mingw 4.9.2 64 bit compilers were used, downloaded from: 307 | 308 | https://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/Previous/1.1309.0/ 309 | 310 | This installs to the directory: 311 | 312 | C:\TDM-GCC-64 313 | 314 | The Qt 4.8.5 / mingw 4.8.2 build was downloaded from: 315 | 316 | https://sourceforge.net/projects/mingwbuilds/files/external-binary-packages/Qt-Builds/ 317 | 318 | The files were extracted, and moved in to the directory: 319 | 320 | C:\Test 321 | 322 | Which seems to be the expected location. 323 | 324 | The mex file was then built within the Git Bash shell: 325 | 326 | #- Set variables: 327 | 328 | export QTBASEDIR="/c/Test" 329 | export QTDIR="${QTBASEDIR}/Qt-4.8.5-x86_64" 330 | export PATH="${QTDIR}/bin:${PATH}" 331 | export CPATH="${QTDIR}/include/QtCore:${CPATH}" 332 | export CPATH="${QTBASEDIR}/prerequisites-x86_64/include:${QTDIR}/include:${CPATH}" 333 | export LIBRARY_PATH="${QTDIR}/lib:${QTBASEDIR}/mingw64/x86_64-w64-mingw32/lib:${LIBRARY_PATH}" 334 | export QMAKESPEC="${QTDIR}/mkspecs/win32-g++" 335 | export MINGWROOT="/c/TDM-GCC-64" 336 | export PATH="${MINGWROOT}/bin:${PATH}" 337 | export GEOPSY_HOME="/c/Users/user/geopsy" 338 | export CPATH="${GEOPSY_HOME}/include:${CPATH}" 339 | export LIBRARY_PATH="${GEOPSY_HOME}/lib:${LIBRARY_PATH}" 340 | export CFLAGS='-O2 -fPIC' 341 | export CXXFLAGS='-O2 -fPIC' 342 | export FFLAGS='-O2 -fPIC' 343 | export FCFLAGS='-O2 -fPIC' 344 | 345 | #- Edit ${QMAKESPEC}/qmake.conf: 346 | 347 | cp ${QMAKESPEC}/qmake.conf \ 348 | ${QMAKESPEC}/qmake.conf.original 349 | sed -i 's|^\(QMAKE_CFLAGS_WARN_ON\).*$|\1 =|g' \ 350 | ${QMAKESPEC}/qmake.conf 351 | sed -i 's|^\(QMAKE_CFLAGS_RELEASE.*$\)|\1 -fpermissive|g' \ 352 | ${QMAKESPEC}/qmake.conf 353 | 354 | #- Copy ${QTDIR}/lib/QTCore4.dll.bak ${QTDIR}/lib/QTCore.dll 355 | 356 | cp ${QTDIR}/lib/QTCore4.dll.bak \ 357 | ${QTDIR}/lib/QTCore.dll 358 | 359 | #- Extract geopsy source, and configure: 360 | 361 | tar xzf geopsypack-55items-src-2.10.1.tar.gz 362 | cd geopsy-2.10.1 363 | 364 | ./configure \ 365 | -prefix ${GEOPSY_HOME} 366 | 367 | # only need to make QGpCoreTools and QGpCoreWave: 368 | 369 | cd QGpCoreTools 370 | cp QGpCoreTools.pro QGpCoreTools.pro.original 371 | sed -i 's|^\(DEFINES.*$\)|\1 QT_DISABLE_DEPRECATED_BEFORE=0 Q_WS_WIN=1|g' \ 372 | QGpCoreTools.pro 373 | sed -i 's|\(LIBS\s.*$\)|\1 -lz|g' \ 374 | QGpCoreTools.pro 375 | 376 | mingw32-make -j16 release 377 | mingw32-make -j16 release-install 378 | cd .. 379 | 380 | \cp include/QGpCoreTools/QGpCoreToolsInstallPath.h \ 381 | ${GEOPSY_HOME}/include/ 382 | 383 | cd QGpCoreWave 384 | cp QGpCoreWave.pro QGpCoreWave.pro.original 385 | sed -i 's|^\(DEFINES.*$\)|\1 QT_DISABLE_DEPRECATED_BEFORE=0 Q_WS_WIN=1|g' \ 386 | QGpCoreWave.pro 387 | sed -i 's|\(LIBS\s.*$\)|\1 -lz|g' \ 388 | QGpCoreWave.pro 389 | 390 | mingw32-make -j16 release 391 | mingw32-make -j16 release-install 392 | cd .. 393 | 394 | \cp include/QGpCoreWave/QGpCoreWaveInstallPath.h \ 395 | ${GEOPSY_HOME}/include/ 396 | 397 | cd .. 398 | 399 | #- Compile mex file: 400 | 401 | MATLAB_HOME='/c/Program Files/MATLAB/R2017a' 402 | 403 | g++ \ 404 | gpdc.cpp \ 405 | -O2 \ 406 | -fpermissive \ 407 | -shared \ 408 | -DMATLAB_MEX_FILE \ 409 | -o gpdc.mexw64 \ 410 | -I"${MATLAB_HOME}/extern/include" \ 411 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmex.lib" \ 412 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmx.lib" \ 413 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libeng.lib" \ 414 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmat.lib" \ 415 | -lQGpCoreTools1 \ 416 | -lQGpCoreWave1 \ 417 | -lQtCore4 418 | 419 | #- As well as the mex file, the following libraries are required to 420 | # be in the same directory: 421 | 422 | \cp \ 423 | ${GEOPSY_HOME}/lib/*.dll \ 424 | ${QTDIR}/lib/QtCore4.dll.bak \ 425 | ${QTBASEDIR}/mingw64/bin/libwinpthread-1.dll \ 426 | ${QTBASEDIR}/mingw64/bin/libgcc_s_seh-1.dll \ 427 | ${QTBASEDIR}/mingw64/bin/libstdc++-6.dll \ 428 | . 429 | 430 | \mv QtCore4.dll.bak QtCore4.dll 431 | 432 | #- 433 | 434 | -------------------------------------------------------------------------------- /gpdc mex file LINUX/gpdc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | matlab mex interface to geopsy dispersion calculation 4 | 5 | * usage: 6 | 7 | out = gpdc(T, Vp, Vs, d) 8 | out = gpdc(T, Vp, Vs, d, 'nSamples', n, 'minRange', mn, 'maxRange', mx) 9 | out = gpdc(T, Vp, Vs, d, 'fV', f) 10 | 11 | where required input: 12 | 13 | T = Thickness(m) : double vector 14 | Vp = Vp (m/s) : double vector 15 | Vs = Vs (m/s) : double vector 16 | d = density (kg/m3) : double vector 17 | 18 | optional input for frequency values. one or more of these options can be set: 19 | 20 | n = number of samples : scalar integer (but in matlab the type would actually be 'double'...) 21 | mn = minimum range : scalar double 22 | mx = maximum range : scalar double 23 | 24 | or, the frequency values can be set form a vector of doubles: 25 | 26 | f = frequency vector : double vector 27 | 28 | if 'fV' is provided 'nSamples', 'minRange' and 'maxRange' values will be ignored. 29 | 30 | example using fV: 31 | 32 | out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 33 | 34 | which should be equivalent to: 35 | 36 | gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 37 | 38 | * output: 39 | 40 | out = 2d matrix 41 | 42 | col1 : x values 43 | col2 : y values for mode 0 44 | col3 : y values for mode 1 45 | ... 46 | 47 | * example: 48 | 49 | T = [7.5, 25, 0]; 50 | Vp = [500, 1350, 2000]; 51 | Vs = [200, 210, 1000]; 52 | d = [1700, 1900, 2500]; 53 | out = gpdc(T, Vp, Vs, d); 54 | plot(out(:, 1), out(:, 2:end)) 55 | 56 | which should be equivalent to (these command line options match our defaults): 57 | 58 | gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 59 | 60 | */ 61 | 62 | /* define name of mex function: */ 63 | #define MEXNAME "gpdc" 64 | 65 | /* include sstream and string for error messaging: */ 66 | #include 67 | /* include matlab mex + matrix headers: */ 68 | #include "mex.h" 69 | #include "matrix.h" 70 | /* geopsy headers: */ 71 | #include 72 | 73 | 74 | /* error messaging function: */ 75 | const char *errorMessage(int msgType, 76 | const char *errorMessage) { 77 | 78 | /* stream for error message: */ 79 | std::stringstream errStr; 80 | /* if type is 0, this is the error id: */ 81 | if (msgType == 0) { 82 | errStr << "MATLAB:" << MEXNAME << ":" << errorMessage; 83 | } else { 84 | /* this is the error message: */ 85 | errStr << MEXNAME << " : " << errorMessage; 86 | } 87 | /* to string ... : */ 88 | std::string errMsg = errStr.str(); 89 | /* return message as char: */ 90 | return errMsg.c_str(); 91 | 92 | } 93 | 94 | 95 | /* function to process model: */ 96 | void processModel(int nLayers, 97 | const mxArray *T, 98 | const mxArray *Vp, 99 | const mxArray *Vs, 100 | const mxArray *d, 101 | const mxArray *nSamplesIn, 102 | const mxArray *minRangeIn, 103 | const mxArray *maxRangeIn, 104 | const mxArray *fV, 105 | mxArray *plhs[]) { 106 | 107 | /* default values: */ 108 | int nRayleigh = 5; /* geopsy default : 1 */ 109 | int nLove = 0; 110 | bool groupSlowness = false; 111 | int nSamples = 150; /* geopsy default : 100 */ 112 | double minRange = 1.0; /* geopsy default : 0.2 */ 113 | double maxRange = 150.0; /* geopsy default : 20.0 */ 114 | int vNSamples = 100; 115 | double vMinRange = 100.0; 116 | double vMaxRange = 3000.0; 117 | bool oneMode = false; 118 | bool force = false; 119 | 120 | /* 121 | mode: 122 | O : GridMode 123 | 1 : CurveMode 124 | */ 125 | enum AppMode {GridMode = 0, CurveMode = 1}; 126 | AppMode mode = CurveMode; 127 | 128 | /* 129 | samplingType: 130 | 0 : LinearScale 131 | 1 : LogScale 132 | 2 : InversedScale 133 | 4 : Interpole 134 | 8 : Function 135 | */ 136 | SamplingOption samplingType = LinearScale; /* geopsy default : LogScale */ 137 | 138 | /* input: */ 139 | double *T_data = (double *) mxGetData(T); 140 | double *Vp_data = (double *) mxGetData(Vp); 141 | double *Vs_data = (double *) mxGetData(Vs); 142 | double *d_data = (double *) mxGetData(d); 143 | std::vector fV_vector; 144 | 145 | /* variables: */ 146 | int i, j; 147 | QVector x; 148 | 149 | /* output: */ 150 | Curve curveOut; 151 | int curveOutCount; 152 | double *mOut = NULL; 153 | 154 | /* check inputs. if nSamples is provided ... : */ 155 | if (nSamplesIn) { 156 | /* get supplied value: */ 157 | double *nSamples_data = (double *) mxGetData(nSamplesIn); 158 | /* should be an integer: */ 159 | if (*nSamples_data != floor(*nSamples_data)) { 160 | /* or exit: */ 161 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 162 | errorMessage(1, "nSamples should be an integer")); 163 | } else { 164 | /* use supplied value: */ 165 | nSamples = floor(*nSamples_data); 166 | } 167 | } 168 | 169 | /* if minRange is not empty ... : */ 170 | if (minRangeIn) { 171 | /* get supplied value: */ 172 | double *minRangePtr = (double *) mxGetData(minRangeIn); 173 | minRange = *minRangePtr; 174 | } 175 | 176 | /* if maxRange is not empty ... : */ 177 | if (maxRangeIn) { 178 | /* get supplied value: */ 179 | double *maxRangePtr = (double *) mxGetData(maxRangeIn); 180 | maxRange = *maxRangePtr; 181 | } 182 | 183 | /* if fV is not empty ... : */ 184 | if (fV) { 185 | double *fV_data = (double *) mxGetData(fV); 186 | /* nSamples is length of fV: */ 187 | nSamples = mxGetN(fV); 188 | /* set fV_vector to appropriate size: */ 189 | fV_vector.resize(nSamples); 190 | /* spin through fV_data: */ 191 | for (i = 0; i < nSamples; i++) { 192 | fV_vector[i] = *fV_data; 193 | *fV_data++; 194 | } 195 | /* sort fV_vector: */ 196 | std::sort(fV_vector.begin(), fV_vector.end()); 197 | /* minRange and maxRange are first and last values: */ 198 | minRange = fV_vector[0]; 199 | maxRange = fV_vector[nSamples - 1]; 200 | } 201 | 202 | /* if no plugincoreapplication instance ... : */ 203 | if (! PluginCoreApplication::instance()) { 204 | /* set up plugincoreapplication: */ 205 | new PluginCoreApplication; 206 | /* disable application output (stout / stderr): */ 207 | PluginCoreApplication::instance()->freezeStream(true); 208 | } 209 | 210 | /* initialise model: */ 211 | LayeredModel model(nLayers); 212 | 213 | /* add data to model: */ 214 | for (i = 0; i < nLayers; i++) { 215 | /* don't set thickness for final layer: */ 216 | if(i < nLayers-1) { 217 | /* add T: */ 218 | model.setH(i, *T_data); 219 | *T_data++; 220 | } 221 | /* add Vp, Vs, d: */ 222 | model.setSlowP(i, 1.0 / *Vp_data); 223 | *Vp_data++; 224 | model.setSlowS(i, 1.0 / *Vs_data); 225 | *Vs_data++; 226 | model.setRho(i, *d_data); 227 | *d_data++; 228 | /* non mandatory quality factors, presume 0: */ 229 | model.setQp(i, 0.0); 230 | model.setQs(i, 0.0); 231 | } 232 | 233 | /* initialise model calculation ... : */ 234 | model.initCalculation(); 235 | 236 | /* compute common sampling scale: */ 237 | Curve curve; 238 | curve.line(minRange, 0.0, maxRange, 0.0); 239 | curve.resample(nSamples, minRange, maxRange, samplingType | Function); 240 | 241 | /* if fV has been supplied ... : */ 242 | if (fV) { 243 | /* spin through the frequency vector: */ 244 | for (i = 0; i < nSamples; i++) { 245 | /* set the curve x value: */ 246 | curve[i].setX(fV_vector[i]); 247 | } 248 | } 249 | 250 | /* convert to angular frequency: */ 251 | curve.xMultiply(2*M_PI); 252 | x = curve.xVector(); 253 | 254 | /* mode switching: */ 255 | switch(mode) { 256 | 257 | /* curve mode (1): */ 258 | case CurveMode: 259 | 260 | /* check number of rayleigh modes: */ 261 | if (nRayleigh > 0) { 262 | /* rayleigh the model ... : */ 263 | Rayleigh rayleigh(&model); 264 | /* initialise dispersion: */ 265 | Dispersion dispersion(nRayleigh, &x); 266 | /* if dispersion can be calculated ... : */ 267 | if (dispersion.calculate(&rayleigh, 0)) { 268 | 269 | /* if using groupSlowness: */ 270 | if (groupSlowness) { 271 | dispersion.setGroupSlowness(); 272 | } 273 | 274 | /* send output curves back to matlab ... init output matrix : x + nRaylegh*y : */ 275 | plhs[0] = mxCreateDoubleMatrix(nSamples, (nRayleigh + 1), mxREAL); 276 | /* get pointer for output: */ 277 | mOut = mxGetPr(plhs[0]); 278 | /* for each rayleigh mode: */ 279 | for (i = 0; i < nRayleigh; i++) { 280 | /* get dispersion curve values ... : */ 281 | curveOut = dispersion.curve(i); 282 | /* get curve value count: */ 283 | curveOutCount = curveOut.count(); 284 | /* if this is mode 0: */ 285 | if (i == 0) { 286 | /* set x values, 1 -> nSamples: */ 287 | for (j = 0; j < curveOutCount; j++) { 288 | const Point2D p = curveOut.at(j); 289 | *mOut = p.x(); 290 | *mOut++; 291 | } 292 | } 293 | /* set any null values ... : */ 294 | for (j = 0; j < (nSamples - curveOutCount); j++) { 295 | *mOut = mxGetNaN(); 296 | *mOut++; 297 | } 298 | /* loop through curve, and set y values: */ 299 | for (j = 0; j < curveOutCount; j++) { 300 | const Point2D p = curveOut.at(j); 301 | *mOut = p.y(); 302 | *mOut++; 303 | } 304 | } 305 | /* end matlab output. */ 306 | 307 | } else if(force) { 308 | /* cannot compute dispersion curves ... : */ 309 | mexErrMsgIdAndTxt(errorMessage(0, "computedispersioncurves"), 310 | errorMessage(1, "cannot compute dispersion curves")); 311 | } else { 312 | /* dispersion calculate failed ... : */ 313 | mexErrMsgIdAndTxt(errorMessage(0, "dispersioncalculate"), 314 | errorMessage(1, "dispersion calculate failed")); 315 | } 316 | 317 | } else { 318 | /* rayleigh number not greater than 0, exit: */ 319 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 320 | errorMessage(0, "rayleigh should be > 0 for curve mode")); 321 | } 322 | 323 | /* curve mode done: */ 324 | break; 325 | 326 | /* default is exit: */ 327 | default: 328 | 329 | /* valid mode not specified: */ 330 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 331 | errorMessage(1, "mode specified is not valid")); 332 | break; 333 | 334 | } 335 | 336 | /* return: */ 337 | return; 338 | 339 | } 340 | 341 | 342 | /* main gateway mexFunction: */ 343 | void mexFunction(int nlhs, mxArray* plhs[], 344 | int nrhs, const mxArray* prhs[]) { 345 | 346 | /* input variables: */ 347 | const mxArray *T = NULL; 348 | const mxArray *Vp = NULL; 349 | const mxArray *Vs = NULL; 350 | const mxArray *d = NULL; 351 | const mxArray *nSamples = NULL; 352 | const mxArray *minRange = NULL; 353 | const mxArray *maxRange = NULL; 354 | const mxArray *fV = NULL; 355 | int nLayers; 356 | 357 | /* variables: */ 358 | int i; 359 | std::stringstream errStr, s; 360 | 361 | /* check number of output arguments is either 0 or 1: */ 362 | if ((nlhs != 0) && 363 | (nlhs != 1)) { 364 | /* or exit: */ 365 | mexErrMsgIdAndTxt(errorMessage(0, "nargout"), 366 | errorMessage(1, "one output argument expected")); 367 | } 368 | 369 | /* check number input of arguments is 4, 6, 8, 10 or 12: */ 370 | if ((nrhs != 4) && 371 | (nrhs != 6) && 372 | (nrhs != 8) && 373 | (nrhs != 10) && 374 | (nrhs != 12)) { 375 | /* or exit: */ 376 | mexErrMsgIdAndTxt(errorMessage(0, "nargin"), 377 | errorMessage(1, "incorrect number of input arguments")); 378 | } 379 | 380 | /* check input arguments ... T: */ 381 | if (!mxIsDouble(prhs[0]) || 382 | mxIsScalar(prhs[0]) || 383 | mxIsComplex(prhs[0])) { 384 | /* or exit: */ 385 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 386 | errorMessage(1, "first input should be double vector : Thickness (m)")); 387 | } else { 388 | /* use supplied value: */ 389 | T = prhs[0]; 390 | } 391 | 392 | /* check input arguments ... Vp: */ 393 | if (!mxIsDouble(prhs[1]) || 394 | mxIsScalar(prhs[1]) || 395 | mxIsComplex(prhs[1])) { 396 | /* or exit: */ 397 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 398 | errorMessage(1, "second input should be double vector : Vp (m/s)")); 399 | } else { 400 | /* use supplied value: */ 401 | Vp = prhs[1]; 402 | } 403 | 404 | /* check input arguments ... Vs: */ 405 | if (!mxIsDouble(prhs[2]) || 406 | mxIsScalar(prhs[2]) || 407 | mxIsComplex(prhs[2])) { 408 | /* or exit: */ 409 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 410 | errorMessage(1, "third input should be double vector : Vs (m/s)")); 411 | } else { 412 | /* use supplied value: */ 413 | Vs = prhs[2]; 414 | } 415 | 416 | /* check input arguments ... d: */ 417 | if (!mxIsDouble(prhs[3]) || 418 | mxIsScalar(prhs[3]) || 419 | mxIsComplex(prhs[3])) { 420 | /* or exit: */ 421 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 422 | errorMessage(1, "fourth input should be double vector : density (kg/m3)")); 423 | } else { 424 | /* use supplied value: */ 425 | d = prhs[3]; 426 | } 427 | 428 | /* 429 | arguments > 3 should be optional key / value pairs, i.e,: 430 | 431 | 'nSamples', 100 432 | 'minRange', 1.0 433 | 'maxRange', 150.0 434 | */ 435 | 436 | /* while 3 < i < number of arguments ... : */ 437 | for (i = 4; i < nrhs; i += 2) { 438 | 439 | /* check this argument is a char: */ 440 | if (mxIsChar(prhs[i])) { 441 | /* check length of argument: */ 442 | mwSize argLen = mxGetN(prhs[i]) + 1; 443 | /* if less than 16 ... : */ 444 | if (argLen < 16) { 445 | /* get argName: */ 446 | char *argName = new char[16]; 447 | mxGetString(prhs[i], argName, argLen); 448 | 449 | /* if nSamples ... : */ 450 | if (strcmp(argName, "nSamples") == 0) { 451 | /* argValue is i+1, and should be an integer: */ 452 | if (!mxIsDouble(prhs[i + 1]) || 453 | !mxIsScalar(prhs[i + 1]) || 454 | mxIsComplex(prhs[i + 1])) { 455 | /* or exit: */ 456 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 457 | errorMessage(1, "input nSamples should be an integer")); 458 | } else { 459 | /* use supplied value: */ 460 | nSamples = prhs[i + 1]; 461 | } 462 | 463 | /* if minRange: */ 464 | } else if (strcmp(argName, "minRange") == 0) { 465 | /* argValue is i+1, and should be a double: */ 466 | if (!mxIsDouble(prhs[i + 1]) || 467 | !mxIsScalar(prhs[i + 1]) || 468 | mxIsComplex(prhs[i + 1])) { 469 | /* or exit: */ 470 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 471 | errorMessage(1, "input minRange should be a double")); 472 | } else { 473 | /* use supplied value: */ 474 | minRange = prhs[i + 1]; 475 | } 476 | 477 | /* if maxRange: */ 478 | } else if (strcmp(argName, "maxRange") == 0) { 479 | /* argValue is i+1, and should be a double: */ 480 | if (!mxIsDouble(prhs[i + 1]) || 481 | !mxIsScalar(prhs[i + 1]) || 482 | mxIsComplex(prhs[i + 1])) { 483 | /* or exit: */ 484 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 485 | errorMessage(1, "input maxRange should be a double")); 486 | } else { 487 | /* use supplied value: */ 488 | maxRange = prhs[i + 1]; 489 | } 490 | 491 | /* if fV (frequency vector): */ 492 | } else if (strcmp(argName, "fV") == 0) { 493 | /* argValue is i+1, and should be a double vector: */ 494 | if (!mxIsDouble(prhs[i + 1]) || 495 | mxIsScalar(prhs[i + 1]) || 496 | mxIsComplex(prhs[i + 1])) { 497 | /* or exit: */ 498 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 499 | errorMessage(1, "input fV should be double vector")); 500 | } else { 501 | /* use supplied value: */ 502 | fV = prhs[i + 1]; 503 | /* fV nullifies nSamples, minRange and maxRange: */ 504 | nSamples = NULL; 505 | minRange = NULL; 506 | maxRange = NULL; 507 | } 508 | 509 | } else { 510 | /* invalid argument name ... convert i to string: */ 511 | s << i; 512 | /* create message: */ 513 | errStr << "invalid argument name '" << argName << "' at position " << s.str(); 514 | /* error and exit ... : */ 515 | mexErrMsgIdAndTxt(errorMessage(0, "nameargin"), 516 | errorMessage(1, errStr.str().c_str())); 517 | } 518 | 519 | } else { 520 | /* invalid argument length (char > 16) ... convert i to string: */ 521 | s << i; 522 | /* create message: */ 523 | errStr << "invalid argument length at position " << s.str(); 524 | /* error and exit ... : */ 525 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 526 | errorMessage(1, errStr.str().c_str())); 527 | } 528 | 529 | } else { 530 | /* invalid argument type ... convert i to string: */ 531 | s << i; 532 | /* create message: */ 533 | errStr << "invalid input argument type at position " << s.str(); 534 | /* error and exit ... : */ 535 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 536 | errorMessage(1, errStr.str().c_str())); 537 | } 538 | 539 | } 540 | /* end argument > 3 */ 541 | 542 | /* check inputs are of the same length: */ 543 | if (mxGetN(T) != mxGetN(Vp) || 544 | mxGetN(Vp) != mxGetN(Vs) || 545 | mxGetN(Vs) != mxGetN(d)) { 546 | /* or exit: */ 547 | mexErrMsgIdAndTxt(errorMessage(0, "lenargin"), 548 | errorMessage(1, "inputs T, Vp, Vs and d should be of equal length")); 549 | } 550 | 551 | /* number of layers: */ 552 | nLayers = mxGetN(T); 553 | /* process model - function sends output back to matlab: */ 554 | processModel(nLayers, T, Vp, Vs, d, nSamples, minRange, maxRange, fV, plhs); 555 | /* return: */ 556 | return; 557 | 558 | } 559 | 560 | -------------------------------------------------------------------------------- /gpdc mex file LINUX/gpdc_test.m: -------------------------------------------------------------------------------- 1 | %- gpdc_test.m 2 | % 3 | % simple gpc test, should be equivalent to running: 4 | % 5 | % gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 6 | 7 | T = [7.5, 25, 0]; 8 | Vp = [500, 1350, 2000]; 9 | Vs = [200, 210, 1000]; 10 | d = [1700, 1900, 2500]; 11 | out = gpdc(T, Vp, Vs, d); 12 | 13 | fig00 = figure; 14 | plot(out(:, 1), out(:, 2:end)); 15 | 16 | fig01 = figure; 17 | plot(out(:, 1), rdivide(1, out(:, 2:end))); 18 | 19 | % same thing, using nSamples, minRange and maxRange: 20 | % out = gpdc(T, Vp, Vs, d, 'minRange', 1.0, 'maxRange', 150.0, 'nSamples', 150); 21 | 22 | % using fV (frequency vector): 23 | % out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 24 | % should be equivalent to: 25 | % gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 26 | 27 | -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/QGpCoreTools1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/QGpCoreTools1.dll -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/QGpCoreWave1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/QGpCoreWave1.dll -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/QtCore4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/QtCore4.dll -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/READ_ME.txt: -------------------------------------------------------------------------------- 1 | #--- gpdc 2 | 3 | A mex interface to the geopsy (http://geopsy.org/) software, to 4 | replicate the functionality of the gpdc program 5 | (http://www.geopsy.org/wiki/index.php/Gpdc). 6 | 7 | The Matlab mex interface replicates much of the geopsy source code found 8 | in the geopsy source file DispersionReader.cpp, but does not implement 9 | all features (e.g. Grid Mode is not implemented). The mex interface also 10 | adds the ability to specify frequency values, rather than just the 11 | minimum and maximum of the range. 12 | 13 | Some defaults differ from the gpdc defaults, and these are noted in the 14 | source code. 15 | 16 | #-- Usage: 17 | 18 | Usage examples: 19 | 20 | out = gpdc(T, Vp, Vs, d) 21 | out = gpdc(T, Vp, Vs, d, 'nSamples', n, 'minRange', mn, 'maxRange', mx) 22 | out = gpdc(T, Vp, Vs, d, 'fV', f) 23 | 24 | Where required input: 25 | 26 | T = Thickness(m) : double vector 27 | Vp = Vp (m/s) : double vector 28 | Vs = Vs (m/s) : double vector 29 | d = density (kg/m3) : double vector 30 | 31 | Optional input for frequency values. One or more of these options can be 32 | set: 33 | 34 | n = number of samples : scalar integer 35 | mn = minimum range : scalar double 36 | mx = maximum range : scalar double 37 | 38 | Alternatively, the frequency values can be set from a vector of doubles: 39 | 40 | f = frequency vector : double vector 41 | 42 | If 'fV' is provided 'nSamples', 'minRange' and 'maxRange' values will be 43 | ignored. 44 | 45 | Example using fV: 46 | 47 | out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 48 | 49 | Which should be equivalent to: 50 | 51 | gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 52 | 53 | #- Output: 54 | 55 | out = 2d matrix 56 | 57 | col1 : x values 58 | col2 : y values for mode 0 59 | col3 : y values for mode 1 60 | ... 61 | 62 | For example: 63 | 64 | T = [7.5, 25, 0]; 65 | Vp = [500, 1350, 2000]; 66 | Vs = [200, 210, 1000]; 67 | d = [1700, 1900, 2500]; 68 | out = gpdc(T, Vp, Vs, d); 69 | plot(out(:, 1), out(:, 2:end)) 70 | 71 | Which should be equivalent to (these command line options match our defaults): 72 | 73 | gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 74 | 75 | #-- Compiling: 76 | 77 | The mex interface has been mostly tested on CentOS 7, and Windows 7, 78 | with Matlab 2017a and geopsy 2.10.0. 79 | 80 | #- Linux: 81 | 82 | Presuming the Matlab bin directory is in the PATH, the geopsy software 83 | is installed at ${GEOPSY_HOME}, and we are using the system version of 84 | Qt, installed within the /usr directory, the mex file can be compiled 85 | with: 86 | 87 | mex gpdc.cpp \ 88 | -I/usr/include/QtCore \ 89 | -L${GEOPSY_HOME} \ 90 | -lQGpCoreTools \ 91 | -lQGpCoreWave \ 92 | LDFLAGS="-Wl,-rpath,${GEOPSY_HOME}/lib" 93 | 94 | Which should produce the file: 95 | 96 | gpdc.mexa64 97 | 98 | Testing has found that if the system version of Qt differs from the 99 | version of Qt used by Matlab, this can cause crashes when using the 100 | Matlab graphical interface. 101 | 102 | To avoid the crashes, the geopsy code and mex code can be compiled using 103 | the same version of Qt as used by Matlab. For example, Matlab 2017a uses 104 | Qt 5.5.1. The build process is a bit more complicated, but does not 105 | require building the entire geopsy suite, as only QGpCoreTools and 106 | QGpCoreWave are used. 107 | 108 | Notes on building Qt 5.5.1, required geopsy libraries, and mex interface 109 | for Matlab 2017a, where everything will be built and installed within 110 | the current working directory. Presumes Matlab is installed at 111 | ${MATLAB_HOME}: 112 | 113 | export CFLAGS='-O2 -fPIC' 114 | export CXXFLAGS='-O2 -fPIC' 115 | export FFLAGS='-O2 -fPIC' 116 | export FCFLAGS='-O2 -fPIC' 117 | 118 | unset QTDIR 119 | unset QTINC 120 | unset QTLIB 121 | 122 | #- Qt 5.5.1: 123 | 124 | wget "http://download.qt.io/archive/qt/5.5/5.5.1/single/qt-everywhere-opensource-src-5.5.1.tar.xz" 125 | tar xJf qt-everywhere-opensource-src-5.5.1.tar.xz 126 | 127 | mkdir build.qt-everywhere-opensource-src-5.5.1 128 | cd build.qt-everywhere-opensource-src-5.5.1 129 | 130 | mkdir ../qt5 131 | qt5Prefix="$(readlink -f ../qt5)" 132 | 133 | ../qt-everywhere-opensource-src-5.5.1/configure \ 134 | -opensource \ 135 | -confirm-license \ 136 | -no-rpath \ 137 | -qt-xcb \ 138 | -no-audio-backend \ 139 | -nomake examples \ 140 | -nomake tests \ 141 | -make libs \ 142 | -prefix ${qt5Prefix} \ 143 | -bindir ${qt5Prefix}/bin && \ 144 | LD_LIBRARY_PATH="$(pwd)/lib:${LD_LIBRARY_PATH}" \ 145 | make -j32 && \ 146 | LD_LIBRARY_PATH="$(pwd)/lib:${LD_LIBRARY_PATH}" \ 147 | make -j32 install && \ 148 | cd .. 149 | 150 | PATH="$(pwd)/qt5/bin:${PATH}" 151 | CPATH="$(pwd)/qt5/include:${CPATH}" 152 | LIBRARY_PATH="$(pwd)/qt5/lib:${LIBRARY_PATH}" 153 | LD_LIBRARY_PATH="$(pwd)/qt5/lib:${LIBRARY_PATH}" 154 | 155 | #- geopsy: 156 | # sources downloaded from: 157 | # http://www.geopsy.org/download.php 158 | 159 | tar xzf geopsypack-55items-src-2.10.1.tar.gz 160 | cd geopsypack-55items-src-2.10.1 161 | 162 | mkdir ../geopsy 163 | gpPrefix="$(readlink -f ../geopsy)" 164 | 165 | echo 'yes' | \ 166 | ./configure \ 167 | -prefix ${gpPrefix} \ 168 | -I ${qt5Prefix}/include \ 169 | -I ${qt5Prefix}/include/QtCore \ 170 | -L ${qt5Prefix}/lib \ 171 | -I ${MATLAB_HOME}/extern/include \ 172 | -L ${MATLAB_HOME}/bin/glnxa64 173 | 174 | # Only need to make QGpCoreTools and QGpCoreWave: 175 | 176 | cd QGpCoreTools 177 | 178 | # Patches for Qt 5.5.1: 179 | 180 | cp src/AbstractStream.h \ 181 | src/AbstractStream.h.original 182 | sed -i 's|fromAscii|fromLatin1|g' \ 183 | src/AbstractStream.h 184 | 185 | cp src/Cache.cpp \ 186 | src/Cache.cpp.original 187 | sed -i 's|toAscii|toLatin1|g' \ 188 | src/Cache.cpp 189 | 190 | cp src/ConsoleProgress.cpp \ 191 | src/ConsoleProgress.cpp.original 192 | sed -i 's|toAscii|toLatin1|g' \ 193 | src/ConsoleProgress.cpp 194 | 195 | cp src/CoreApplicationPrivate.cpp \ 196 | src/CoreApplicationPrivate.cpp.original 197 | sed -i 's|toAscii|toLatin1|g' \ 198 | src/CoreApplicationPrivate.cpp 199 | sed -i '/qInstallMsgHandler/d' \ 200 | src/CoreApplicationPrivate.cpp 201 | 202 | cp src/XMLClass.cpp \ 203 | src/XMLClass.cpp.original 204 | sed -i 's|toAscii|toLatin1|g' \ 205 | src/XMLClass.cpp 206 | 207 | cp src/Tar.cpp \ 208 | src/Tar.cpp.original 209 | sed -i 's|toAscii|toLatin1|g' \ 210 | src/Tar.cpp 211 | 212 | cp src/XMLParser.cpp \ 213 | src/XMLParser.cpp.original 214 | sed -i 's|toAscii|toLatin1|g' \ 215 | src/XMLParser.cpp 216 | 217 | cp src/Thread.cpp \ 218 | src/Thread.cpp.original 219 | sed -i '/QThread::finished()/d' \ 220 | src/Thread.cpp 221 | 222 | make -j16 release 223 | make -j16 release-install 224 | cd .. 225 | 226 | \cp include/QGpCoreTools/QGpCoreToolsInstallPath.h \ 227 | ${gpPrefix}/include/ 228 | 229 | cd QGpCoreWave 230 | 231 | make -j16 release 232 | make -j16 release-install 233 | cd .. 234 | 235 | \cp include/QGpCoreWave/QGpCoreWaveInstallPath.h \ 236 | ${gpPrefix}/include/ 237 | 238 | cd .. 239 | 240 | #- mex file - presume mex source is already in 'mex' directory ... : 241 | 242 | cd mex 243 | 244 | g++ \ 245 | gpdc.cpp \ 246 | -O2 \ 247 | -fPIC \ 248 | -fpermissive \ 249 | -shared \ 250 | -DMATLAB_MEX_FILE \ 251 | -o gpdc.mexa64 \ 252 | -I${gpPrefix}/include \ 253 | -I${qt5Prefix}/include \ 254 | -I${qt5Prefix}/include/QtCore \ 255 | -I${MATLAB_HOME}/extern/include \ 256 | -L${MATLAB_HOME}/bin/glnxa64 \ 257 | -lmex \ 258 | -lmx \ 259 | -leng \ 260 | -lmat \ 261 | -L${qt5Prefix}/lib \ 262 | -lQt5Core \ 263 | -L${gpPrefix}/lib \ 264 | -lQGpCoreTools \ 265 | -lQGpCoreWave 266 | 267 | This will build the file gpdc.mexa64, which will require the libraries 268 | ${gpPrefix}/libQGpCoreTools.so.1 and ${gpPrefix}/libQGpCoreWave.so.1 to 269 | run. 270 | 271 | For the end user, using the patchelf (https://nixos.org/patchelf.html) 272 | program to set the appropriate RPATH for these files is recommended. 273 | 274 | For example, if the mex file was to be installed at and run from the 275 | directory ${HOME}/matlab/gpc, the required files can be copied in to 276 | place: 277 | 278 | ${HOME}/matlab/gpdc/ 279 | ├── gpdc.mexa64 280 | └── lib/ 281 | ├── libQGpCoreTools.so.1 282 | └── libQGpCoreWave.so.1 283 | 284 | The following patchelf commands can then be used to set appropriate 285 | RPATH values for the files: 286 | 287 | patchelf --remove-rpath ${HOME}/matlab/gpdc/gpdc.mexa64 288 | patchelf --remove-rpath ${HOME}/matlab/gpdc/lib/libQGpCoreTools.so.1 289 | patchelf --remove-rpath ${HOME}/matlab/gpdc/lib/libQGpCoreWave.so.1 290 | patchelf \ 291 | --set-rpath \ 292 | ${MATLAB_HOME}/sys/os/glnxa64:${MATLAB_HOME}/bin/glnxa64:${HOME}/matlab/gpdc/lib \ 293 | gpdc.mexa64 294 | 295 | The directory ${HOME}/matlab/gpdc can then be added to the Matlab path 296 | using the preferred method. 297 | 298 | #- Windows: 299 | 300 | People who are more used to doing this kind of thing in Windows may know 301 | better ways of doing this ... 302 | 303 | Building on Windows (Windows 7 / Matlab 2017a) was done within a Git 304 | Bash shell (https://git-scm.com/download/win). 305 | 306 | TDM mingw 4.9.2 64 bit compilers were used, downloaded from: 307 | 308 | https://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/Previous/1.1309.0/ 309 | 310 | This installs to the directory: 311 | 312 | C:\TDM-GCC-64 313 | 314 | The Qt 4.8.5 / mingw 4.8.2 build was downloaded from: 315 | 316 | https://sourceforge.net/projects/mingwbuilds/files/external-binary-packages/Qt-Builds/ 317 | 318 | The files were extracted, and moved in to the directory: 319 | 320 | C:\Test 321 | 322 | Which seems to be the expected location. 323 | 324 | The mex file was then built within the Git Bash shell: 325 | 326 | #- Set variables: 327 | 328 | export QTBASEDIR="/c/Test" 329 | export QTDIR="${QTBASEDIR}/Qt-4.8.5-x86_64" 330 | export PATH="${QTDIR}/bin:${PATH}" 331 | export CPATH="${QTDIR}/include/QtCore:${CPATH}" 332 | export CPATH="${QTBASEDIR}/prerequisites-x86_64/include:${QTDIR}/include:${CPATH}" 333 | export LIBRARY_PATH="${QTDIR}/lib:${QTBASEDIR}/mingw64/x86_64-w64-mingw32/lib:${LIBRARY_PATH}" 334 | export QMAKESPEC="${QTDIR}/mkspecs/win32-g++" 335 | export MINGWROOT="/c/TDM-GCC-64" 336 | export PATH="${MINGWROOT}/bin:${PATH}" 337 | export GEOPSY_HOME="/c/Users/user/geopsy" 338 | export CPATH="${GEOPSY_HOME}/include:${CPATH}" 339 | export LIBRARY_PATH="${GEOPSY_HOME}/lib:${LIBRARY_PATH}" 340 | export CFLAGS='-O2 -fPIC' 341 | export CXXFLAGS='-O2 -fPIC' 342 | export FFLAGS='-O2 -fPIC' 343 | export FCFLAGS='-O2 -fPIC' 344 | 345 | #- Edit ${QMAKESPEC}/qmake.conf: 346 | 347 | cp ${QMAKESPEC}/qmake.conf \ 348 | ${QMAKESPEC}/qmake.conf.original 349 | sed -i 's|^\(QMAKE_CFLAGS_WARN_ON\).*$|\1 =|g' \ 350 | ${QMAKESPEC}/qmake.conf 351 | sed -i 's|^\(QMAKE_CFLAGS_RELEASE.*$\)|\1 -fpermissive|g' \ 352 | ${QMAKESPEC}/qmake.conf 353 | 354 | #- Copy ${QTDIR}/lib/QTCore4.dll.bak ${QTDIR}/lib/QTCore.dll 355 | 356 | cp ${QTDIR}/lib/QTCore4.dll.bak \ 357 | ${QTDIR}/lib/QTCore.dll 358 | 359 | #- Extract geopsy source, and configure: 360 | 361 | tar xzf geopsypack-55items-src-2.10.1.tar.gz 362 | cd geopsy-2.10.1 363 | 364 | ./configure \ 365 | -prefix ${GEOPSY_HOME} 366 | 367 | # only need to make QGpCoreTools and QGpCoreWave: 368 | 369 | cd QGpCoreTools 370 | cp QGpCoreTools.pro QGpCoreTools.pro.original 371 | sed -i 's|^\(DEFINES.*$\)|\1 QT_DISABLE_DEPRECATED_BEFORE=0 Q_WS_WIN=1|g' \ 372 | QGpCoreTools.pro 373 | sed -i 's|\(LIBS\s.*$\)|\1 -lz|g' \ 374 | QGpCoreTools.pro 375 | 376 | mingw32-make -j16 release 377 | mingw32-make -j16 release-install 378 | cd .. 379 | 380 | \cp include/QGpCoreTools/QGpCoreToolsInstallPath.h \ 381 | ${GEOPSY_HOME}/include/ 382 | 383 | cd QGpCoreWave 384 | cp QGpCoreWave.pro QGpCoreWave.pro.original 385 | sed -i 's|^\(DEFINES.*$\)|\1 QT_DISABLE_DEPRECATED_BEFORE=0 Q_WS_WIN=1|g' \ 386 | QGpCoreWave.pro 387 | sed -i 's|\(LIBS\s.*$\)|\1 -lz|g' \ 388 | QGpCoreWave.pro 389 | 390 | mingw32-make -j16 release 391 | mingw32-make -j16 release-install 392 | cd .. 393 | 394 | \cp include/QGpCoreWave/QGpCoreWaveInstallPath.h \ 395 | ${GEOPSY_HOME}/include/ 396 | 397 | cd .. 398 | 399 | #- Compile mex file: 400 | 401 | MATLAB_HOME='/c/Program Files/MATLAB/R2017a' 402 | 403 | g++ \ 404 | gpdc.cpp \ 405 | -O2 \ 406 | -fpermissive \ 407 | -shared \ 408 | -DMATLAB_MEX_FILE \ 409 | -o gpdc.mexw64 \ 410 | -I"${MATLAB_HOME}/extern/include" \ 411 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmex.lib" \ 412 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmx.lib" \ 413 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libeng.lib" \ 414 | "${MATLAB_HOME}/extern/lib/win64/mingw64/libmat.lib" \ 415 | -lQGpCoreTools1 \ 416 | -lQGpCoreWave1 \ 417 | -lQtCore4 418 | 419 | #- As well as the mex file, the following libraries are required to 420 | # be in the same directory: 421 | 422 | \cp \ 423 | ${GEOPSY_HOME}/lib/*.dll \ 424 | ${QTDIR}/lib/QtCore4.dll.bak \ 425 | ${QTBASEDIR}/mingw64/bin/libwinpthread-1.dll \ 426 | ${QTBASEDIR}/mingw64/bin/libgcc_s_seh-1.dll \ 427 | ${QTBASEDIR}/mingw64/bin/libstdc++-6.dll \ 428 | . 429 | 430 | \mv QtCore4.dll.bak QtCore4.dll 431 | 432 | #- 433 | 434 | -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/gpdc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | matlab mex interface to geopsy dispersion calculation 4 | 5 | * usage: 6 | 7 | out = gpdc(T, Vp, Vs, d) 8 | out = gpdc(T, Vp, Vs, d, 'nSamples', n, 'minRange', mn, 'maxRange', mx) 9 | out = gpdc(T, Vp, Vs, d, 'fV', f) 10 | 11 | where required input: 12 | 13 | T = Thickness(m) : double vector 14 | Vp = Vp (m/s) : double vector 15 | Vs = Vs (m/s) : double vector 16 | d = density (kg/m3) : double vector 17 | 18 | optional input for frequency values. one or more of these options can be set: 19 | 20 | n = number of samples : scalar integer (but in matlab the type would actually be 'double'...) 21 | mn = minimum range : scalar double 22 | mx = maximum range : scalar double 23 | 24 | or, the frequency values can be set form a vector of doubles: 25 | 26 | f = frequency vector : double vector 27 | 28 | if 'fV' is provided 'nSamples', 'minRange' and 'maxRange' values will be ignored. 29 | 30 | example using fV: 31 | 32 | out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 33 | 34 | which should be equivalent to: 35 | 36 | gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 37 | 38 | * output: 39 | 40 | out = 2d matrix 41 | 42 | col1 : x values 43 | col2 : y values for mode 0 44 | col3 : y values for mode 1 45 | ... 46 | 47 | * example: 48 | 49 | T = [7.5, 25, 0]; 50 | Vp = [500, 1350, 2000]; 51 | Vs = [200, 210, 1000]; 52 | d = [1700, 1900, 2500]; 53 | out = gpdc(T, Vp, Vs, d); 54 | plot(out(:, 1), out(:, 2:end)) 55 | 56 | which should be equivalent to (these command line options match our defaults): 57 | 58 | gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 59 | 60 | */ 61 | 62 | /* define name of mex function: */ 63 | #define MEXNAME "gpdc" 64 | 65 | /* include sstream and string for error messaging: */ 66 | #include 67 | /* include matlab mex + matrix headers: */ 68 | #include "mex.h" 69 | #include "matrix.h" 70 | /* geopsy headers: */ 71 | #include 72 | 73 | 74 | /* error messaging function: */ 75 | const char *errorMessage(int msgType, 76 | const char *errorMessage) { 77 | 78 | /* stream for error message: */ 79 | std::stringstream errStr; 80 | /* if type is 0, this is the error id: */ 81 | if (msgType == 0) { 82 | errStr << "MATLAB:" << MEXNAME << ":" << errorMessage; 83 | } else { 84 | /* this is the error message: */ 85 | errStr << MEXNAME << " : " << errorMessage; 86 | } 87 | /* to string ... : */ 88 | std::string errMsg = errStr.str(); 89 | /* return message as char: */ 90 | return errMsg.c_str(); 91 | 92 | } 93 | 94 | 95 | /* function to process model: */ 96 | void processModel(int nLayers, 97 | const mxArray *T, 98 | const mxArray *Vp, 99 | const mxArray *Vs, 100 | const mxArray *d, 101 | const mxArray *nSamplesIn, 102 | const mxArray *minRangeIn, 103 | const mxArray *maxRangeIn, 104 | const mxArray *fV, 105 | mxArray *plhs[]) { 106 | 107 | /* default values: */ 108 | int nRayleigh = 5; /* default : 1 */ 109 | int nLove = 0; 110 | bool groupSlowness = false; 111 | int nSamples = 150; /* default : 100 */ 112 | double minRange = 1.0; /* default : 0.2 */ 113 | double maxRange = 150.0; /* default : 20.0 */ 114 | int vNSamples = 100; 115 | double vMinRange = 100.0; 116 | double vMaxRange = 3000.0; 117 | bool oneMode = false; 118 | bool force = false; 119 | 120 | /* 121 | mode: 122 | O : GridMode 123 | 1 : CurveMode 124 | */ 125 | enum AppMode {GridMode = 0, CurveMode = 1}; 126 | AppMode mode = CurveMode; 127 | 128 | /* 129 | samplingType: 130 | 0 : LinearScale 131 | 1 : LogScale 132 | 2 : InversedScale 133 | 4 : Interpole 134 | 8 : Function 135 | */ 136 | SamplingOption samplingType = LinearScale; /* default : LogScale */ 137 | 138 | /* input: */ 139 | double *T_data = (double *) mxGetData(T); 140 | double *Vp_data = (double *) mxGetData(Vp); 141 | double *Vs_data = (double *) mxGetData(Vs); 142 | double *d_data = (double *) mxGetData(d); 143 | std::vector fV_vector; 144 | 145 | /* variables: */ 146 | int i, j; 147 | QVector x; 148 | 149 | /* output: */ 150 | Curve curveOut; 151 | int curveOutCount; 152 | double *mOut = NULL; 153 | 154 | /* check inputs. if nSamples is provided ... : */ 155 | if (nSamplesIn) { 156 | /* get supplied value: */ 157 | double *nSamples_data = (double *) mxGetData(nSamplesIn); 158 | /* should be an integer: */ 159 | if (*nSamples_data != floor(*nSamples_data)) { 160 | /* or exit: */ 161 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 162 | errorMessage(1, "nSamples should be an integer")); 163 | } else { 164 | /* use supplied value: */ 165 | nSamples = floor(*nSamples_data); 166 | } 167 | } 168 | 169 | /* if minRange is not empty ... : */ 170 | if (minRangeIn) { 171 | /* get supplied value: */ 172 | double *minRangePtr = (double *) mxGetData(minRangeIn); 173 | minRange = *minRangePtr; 174 | } 175 | 176 | /* if maxRange is not empty ... : */ 177 | if (maxRangeIn) { 178 | /* get supplied value: */ 179 | double *maxRangePtr = (double *) mxGetData(maxRangeIn); 180 | maxRange = *maxRangePtr; 181 | } 182 | 183 | /* if fV is not empty ... : */ 184 | if (fV) { 185 | double *fV_data = (double *) mxGetData(fV); 186 | /* nSamples is length of fV: */ 187 | nSamples = mxGetN(fV); 188 | /* set fV_vector to appropriate size: */ 189 | fV_vector.resize(nSamples); 190 | /* spin through fV_data: */ 191 | for (i = 0; i < nSamples; i++) { 192 | fV_vector[i] = *fV_data; 193 | *fV_data++; 194 | } 195 | /* sort fV_vector: */ 196 | std::sort(fV_vector.begin(), fV_vector.end()); 197 | /* minRange and maxRange are first and last values: */ 198 | minRange = fV_vector[0]; 199 | maxRange = fV_vector[nSamples - 1]; 200 | } 201 | 202 | /* if no plugincoreapplication instance ... : */ 203 | if (! PluginCoreApplication::instance()) { 204 | /* set up plugincoreapplication: */ 205 | new PluginCoreApplication; 206 | /* disable application output (stout / stderr): */ 207 | PluginCoreApplication::instance()->freezeStream(true); 208 | } 209 | 210 | /* initialise model: */ 211 | LayeredModel model(nLayers); 212 | 213 | /* add data to model: */ 214 | for (i = 0; i < nLayers; i++) { 215 | /* don't set thickness for final layer: */ 216 | if(i < nLayers-1) { 217 | /* add T: */ 218 | model.setH(i, *T_data); 219 | *T_data++; 220 | } 221 | /* add Vp, Vs, d: */ 222 | model.setSlowP(i, 1.0 / *Vp_data); 223 | *Vp_data++; 224 | model.setSlowS(i, 1.0 / *Vs_data); 225 | *Vs_data++; 226 | model.setRho(i, *d_data); 227 | *d_data++; 228 | /* non mandatory quality factors, presume 0: */ 229 | model.setQp(i, 0.0); 230 | model.setQs(i, 0.0); 231 | } 232 | 233 | /* initialise model calculation ... : */ 234 | model.initCalculation(); 235 | 236 | /* compute common sampling scale: */ 237 | Curve curve; 238 | curve.line(minRange, 0.0, maxRange, 0.0); 239 | curve.resample(nSamples, minRange, maxRange, samplingType | Function); 240 | 241 | /* if fV has been supplied ... : */ 242 | if (fV) { 243 | /* spin through the frequency vector: */ 244 | for (i = 0; i < nSamples; i++) { 245 | /* set the curve x value: */ 246 | curve[i].setX(fV_vector[i]); 247 | } 248 | } 249 | 250 | /* convert to angular frequency: */ 251 | curve.xMultiply(2*M_PI); 252 | x = curve.xVector(); 253 | 254 | /* mode switching: */ 255 | switch(mode) { 256 | 257 | /* curve mode (1): */ 258 | case CurveMode: 259 | 260 | /* check number of rayleigh modes: */ 261 | if (nRayleigh > 0) { 262 | /* rayleigh the model ... : */ 263 | Rayleigh rayleigh(&model); 264 | /* initialise dispersion: */ 265 | Dispersion dispersion(nRayleigh, &x); 266 | /* if dispersion can be calculated ... : */ 267 | if (dispersion.calculate(&rayleigh, 0)) { 268 | 269 | /* if using groupSlowness: */ 270 | if (groupSlowness) { 271 | dispersion.setGroupSlowness(); 272 | } 273 | 274 | /* send output curves back to matlab ... init output matrix : x + nRaylegh*y : */ 275 | plhs[0] = mxCreateDoubleMatrix(nSamples, (nRayleigh + 1), mxREAL); 276 | /* get pointer for output: */ 277 | mOut = mxGetPr(plhs[0]); 278 | /* for each rayleigh mode: */ 279 | for (i = 0; i < nRayleigh; i++) { 280 | /* get dispersion curve values ... : */ 281 | curveOut = dispersion.curve(i); 282 | /* get curve value count: */ 283 | curveOutCount = curveOut.count(); 284 | /* if this is mode 0: */ 285 | if (i == 0) { 286 | /* set x values, 1 -> nSamples: */ 287 | for (j = 0; j < curveOutCount; j++) { 288 | const Point2D p = curveOut.at(j); 289 | *mOut = p.x(); 290 | *mOut++; 291 | } 292 | } 293 | /* set any null values ... : */ 294 | for (j = 0; j < (nSamples - curveOutCount); j++) { 295 | *mOut = mxGetNaN(); 296 | *mOut++; 297 | } 298 | /* loop through curve, and set y values: */ 299 | for (j = 0; j < curveOutCount; j++) { 300 | const Point2D p = curveOut.at(j); 301 | *mOut = p.y(); 302 | *mOut++; 303 | } 304 | } 305 | /* end matlab output. */ 306 | 307 | } else if(force) { 308 | /* cannot compute dispersion curves ... : */ 309 | mexErrMsgIdAndTxt(errorMessage(0, "computedispersioncurves"), 310 | errorMessage(1, "cannot compute dispersion curves")); 311 | } else { 312 | /* dispersion calculate failed ... : */ 313 | mexErrMsgIdAndTxt(errorMessage(0, "dispersioncalculate"), 314 | errorMessage(1, "dispersion calculate failed")); 315 | } 316 | 317 | } else { 318 | /* rayleigh number not greater than 0, exit: */ 319 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 320 | errorMessage(0, "rayleigh should be > 0 for curve mode")); 321 | } 322 | 323 | /* curve mode done: */ 324 | break; 325 | 326 | /* default is exit: */ 327 | default: 328 | 329 | /* valid mode not specified: */ 330 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 331 | errorMessage(1, "mode specified is not valid")); 332 | break; 333 | 334 | } 335 | 336 | /* return: */ 337 | return; 338 | 339 | } 340 | 341 | 342 | /* main gateway mexFunction: */ 343 | void mexFunction(int nlhs, mxArray* plhs[], 344 | int nrhs, const mxArray* prhs[]) { 345 | 346 | /* input variables: */ 347 | const mxArray *T = NULL; 348 | const mxArray *Vp = NULL; 349 | const mxArray *Vs = NULL; 350 | const mxArray *d = NULL; 351 | const mxArray *nSamples = NULL; 352 | const mxArray *minRange = NULL; 353 | const mxArray *maxRange = NULL; 354 | const mxArray *fV = NULL; 355 | int nLayers; 356 | 357 | /* variables: */ 358 | int i; 359 | std::stringstream errStr, s; 360 | 361 | /* check number of output arguments is either 0 or 1: */ 362 | if ((nlhs != 0) && 363 | (nlhs != 1)) { 364 | /* or exit: */ 365 | mexErrMsgIdAndTxt(errorMessage(0, "nargout"), 366 | errorMessage(1, "one output argument expected")); 367 | } 368 | 369 | /* check number input of arguments is 4, 6, 8, 10 or 12: */ 370 | if ((nrhs != 4) && 371 | (nrhs != 6) && 372 | (nrhs != 8) && 373 | (nrhs != 10) && 374 | (nrhs != 12)) { 375 | /* or exit: */ 376 | mexErrMsgIdAndTxt(errorMessage(0, "nargin"), 377 | errorMessage(1, "incorrect number of input arguments")); 378 | } 379 | 380 | /* check input arguments ... T: */ 381 | if (!mxIsDouble(prhs[0]) || 382 | mxIsScalar(prhs[0]) || 383 | mxIsComplex(prhs[0])) { 384 | /* or exit: */ 385 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 386 | errorMessage(1, "first input should be double vector : Thickness (m)")); 387 | } else { 388 | /* use supplied value: */ 389 | T = prhs[0]; 390 | } 391 | 392 | /* check input arguments ... Vp: */ 393 | if (!mxIsDouble(prhs[1]) || 394 | mxIsScalar(prhs[1]) || 395 | mxIsComplex(prhs[1])) { 396 | /* or exit: */ 397 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 398 | errorMessage(1, "second input should be double vector : Vp (m/s)")); 399 | } else { 400 | /* use supplied value: */ 401 | Vp = prhs[1]; 402 | } 403 | 404 | /* check input arguments ... Vs: */ 405 | if (!mxIsDouble(prhs[2]) || 406 | mxIsScalar(prhs[2]) || 407 | mxIsComplex(prhs[2])) { 408 | /* or exit: */ 409 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 410 | errorMessage(1, "third input should be double vector : Vs (m/s)")); 411 | } else { 412 | /* use supplied value: */ 413 | Vs = prhs[2]; 414 | } 415 | 416 | /* check input arguments ... d: */ 417 | if (!mxIsDouble(prhs[3]) || 418 | mxIsScalar(prhs[3]) || 419 | mxIsComplex(prhs[3])) { 420 | /* or exit: */ 421 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 422 | errorMessage(1, "fourth input should be double vector : density (kg/m3)")); 423 | } else { 424 | /* use supplied value: */ 425 | d = prhs[3]; 426 | } 427 | 428 | /* 429 | arguments > 3 should be optional key / value pairs, i.e,: 430 | 431 | 'nSamples', 100 432 | 'minRange', 1.0 433 | 'maxRange', 150.0 434 | */ 435 | 436 | /* while 3 < i < number of arguments ... : */ 437 | for (i = 4; i < nrhs; i += 2) { 438 | 439 | /* check this argument is a char: */ 440 | if (mxIsChar(prhs[i])) { 441 | /* check length of argument: */ 442 | mwSize argLen = mxGetN(prhs[i]) + 1; 443 | /* if less than 16 ... : */ 444 | if (argLen < 16) { 445 | /* get argName: */ 446 | char *argName = new char[16]; 447 | mxGetString(prhs[i], argName, argLen); 448 | 449 | /* if nSamples ... : */ 450 | if (strcmp(argName, "nSamples") == 0) { 451 | /* argValue is i+1, and should be an integer: */ 452 | if (!mxIsDouble(prhs[i + 1]) || 453 | !mxIsScalar(prhs[i + 1]) || 454 | mxIsComplex(prhs[i + 1])) { 455 | /* or exit: */ 456 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 457 | errorMessage(1, "input nSamples should be an integer")); 458 | } else { 459 | /* use supplied value: */ 460 | nSamples = prhs[i + 1]; 461 | } 462 | 463 | /* if minRange: */ 464 | } else if (strcmp(argName, "minRange") == 0) { 465 | /* argValue is i+1, and should be a double: */ 466 | if (!mxIsDouble(prhs[i + 1]) || 467 | !mxIsScalar(prhs[i + 1]) || 468 | mxIsComplex(prhs[i + 1])) { 469 | /* or exit: */ 470 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 471 | errorMessage(1, "input minRange should be a double")); 472 | } else { 473 | /* use supplied value: */ 474 | minRange = prhs[i + 1]; 475 | } 476 | 477 | /* if maxRange: */ 478 | } else if (strcmp(argName, "maxRange") == 0) { 479 | /* argValue is i+1, and should be a double: */ 480 | if (!mxIsDouble(prhs[i + 1]) || 481 | !mxIsScalar(prhs[i + 1]) || 482 | mxIsComplex(prhs[i + 1])) { 483 | /* or exit: */ 484 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 485 | errorMessage(1, "input maxRange should be a double")); 486 | } else { 487 | /* use supplied value: */ 488 | maxRange = prhs[i + 1]; 489 | } 490 | 491 | /* if fV (frequency vector): */ 492 | } else if (strcmp(argName, "fV") == 0) { 493 | /* argValue is i+1, and should be a double vector: */ 494 | if (!mxIsDouble(prhs[i + 1]) || 495 | mxIsScalar(prhs[i + 1]) || 496 | mxIsComplex(prhs[i + 1])) { 497 | /* or exit: */ 498 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 499 | errorMessage(1, "input fV should be double vector")); 500 | } else { 501 | /* use supplied value: */ 502 | fV = prhs[i + 1]; 503 | /* fV nullifies nSamples, minRange and maxRange: */ 504 | nSamples = NULL; 505 | minRange = NULL; 506 | maxRange = NULL; 507 | } 508 | 509 | } else { 510 | /* invalid argument name ... convert i to string: */ 511 | s << i; 512 | /* create message: */ 513 | errStr << "invalid argument name '" << argName << "' at position " << s.str(); 514 | /* error and exit ... : */ 515 | mexErrMsgIdAndTxt(errorMessage(0, "nameargin"), 516 | errorMessage(1, errStr.str().c_str())); 517 | } 518 | 519 | } else { 520 | /* invalid argument length (char > 16) ... convert i to string: */ 521 | s << i; 522 | /* create message: */ 523 | errStr << "invalid argument length at position " << s.str(); 524 | /* error and exit ... : */ 525 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 526 | errorMessage(1, errStr.str().c_str())); 527 | } 528 | 529 | } else { 530 | /* invalid argument type ... convert i to string: */ 531 | s << i; 532 | /* create message: */ 533 | errStr << "invalid input argument type at position " << s.str(); 534 | /* error and exit ... : */ 535 | mexErrMsgIdAndTxt(errorMessage(0, "typeargin"), 536 | errorMessage(1, errStr.str().c_str())); 537 | } 538 | 539 | } 540 | /* end argument > 3 */ 541 | 542 | /* check inputs are of the same length: */ 543 | if (mxGetN(T) != mxGetN(Vp) || 544 | mxGetN(Vp) != mxGetN(Vs) || 545 | mxGetN(Vs) != mxGetN(d)) { 546 | /* or exit: */ 547 | mexErrMsgIdAndTxt(errorMessage(0, "lenargin"), 548 | errorMessage(1, "inputs T, Vp, Vs and d should be of equal length")); 549 | } 550 | 551 | /* number of layers: */ 552 | nLayers = mxGetN(T); 553 | /* process model - function sends output back to matlab: */ 554 | processModel(nLayers, T, Vp, Vs, d, nSamples, minRange, maxRange, fV, plhs); 555 | /* return: */ 556 | return; 557 | 558 | } 559 | 560 | -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/gpdc.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/gpdc.mexw64 -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/gpdc_test.m: -------------------------------------------------------------------------------- 1 | % gpdc -R 5 -s frequency -n 150 -min 1.0 -max 150.0 test.model | figue -c 2 | 3 | T = [7.5, 25, 0]; 4 | Vp = [500, 1350, 2000]; 5 | Vs = [200, 210, 1000]; 6 | d = [1700, 1900, 2500]; 7 | freq = linspace(1,150,150); 8 | out = gpdc(T, Vp, Vs, d, 'fV', freq); 9 | 10 | fig00 = figure; 11 | plot(out(:, 1), out(:, 2:end)); 12 | 13 | fig01 = figure; 14 | plot(out(:, 1), rdivide(1, out(:, 2:end))); 15 | 16 | % same thing, using nSamples, minRange and maxRange: 17 | % out = gpdc(T, Vp, Vs, d, 'minRange', 1.0, 'maxRange', 150.0, 'nSamples', 150); 18 | 19 | % using fV (frequency vector): 20 | % out = gpdc(T, Vp, Vs, d, 'fV', [10, 20, 30]); 21 | % should be equivalent to: 22 | % gpdc -R 5 -s frequency -n 3 -min 10.0 -max 30.0 test.model 23 | 24 | -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/libgcc_s_seh-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/libgcc_s_seh-1.dll -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/libstdc++-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/libstdc++-6.dll -------------------------------------------------------------------------------- /gpdc mex file WINDOWS/libwinpthread-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/gpdc mex file WINDOWS/libwinpthread-1.dll -------------------------------------------------------------------------------- /tools/Plotting_1D_PDFs.m: -------------------------------------------------------------------------------- 1 | close all 2 | 3 | %%%%%%%%%%%%%%%%%%%%%%INPUT PLOTTING PARAMETERS%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | load('output_data.mat') % load results 5 | load('cmap.mat') % load colourbar for plotting PDF's 6 | 7 | multi = 1; % multi = 1 non constrained inversion where num_layers = 1, 8 | % multi = 2 constrained MuLTI inversion, 9 | % multi = 3 MuLTI III inversion (constrained or non-constrained) Vp, Vs and density PDF's, 10 | % multi = 6 MuLTI III inversion, plot all PDF's including Vp, 11 | % Vs, density, shear mod, bulk mod, Vp/Vs and PR 12 | %(all constrained cases are assuming num_layers = 3) 13 | 14 | solution = 1; % 0 = average ; 1 = mode (choose solution to plot on Vp, Vs and density PDF) 15 | 16 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%PLOT 1D RESULTS%%%%%%%%%%%%%%%%%%%%%%%%%%% 17 | % VS plot (Normalised) 18 | figure 19 | subplot(2,3,[1 4]) 20 | contourf(vs_edge,depth_edge,CI_density_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 21 | hold on 22 | if solution == 1 23 | plot(vs_mode_n0,x,'k','LineWidth',2); % mode solution 24 | else 25 | plot(AV,x,'k','LineWidth',2); % average solution 26 | end 27 | title('Shear Wave Velocity PDF'); 28 | % Create ylabel 29 | ylabel('Depth (m)'); 30 | % Create xlabel 31 | xlabel('Vs (m/s)'); 32 | set(gca,'Ydir','reverse') 33 | set(gca,'fontsize',14); 34 | colormap(cm) 35 | colorbar 36 | caxis([0 0.3]) 37 | xlim([500 2500]) 38 | 39 | if multi == 1 %multi non constrained 40 | subplot(2,3,[2 5]) 41 | plot((priors.vp.*ones(dis)),x,'r','LineWidth',2); %input sd vp 42 | title('P Wave Velocity PDF'); 43 | % Create ylabel 44 | ylabel('Depth (m)'); 45 | % Create xlabel 46 | xlabel('Vp (m/s)'); 47 | set(gca,'Ydir','reverse') 48 | set(gca,'fontsize',14); 49 | xlim([1500 4000]) 50 | ylim([0 50]) 51 | 52 | subplot(2,3,[3 6]) 53 | plot((priors.density.*ones(dis)),x,'r','LineWidth',2); %input sd density 54 | title('Density PDF'); 55 | % Create ylabel 56 | ylabel('Depth (m)'); 57 | % Create xlabel 58 | xlabel('Density (g/cc)'); 59 | set(gca,'Ydir','reverse') 60 | set(gca,'fontsize',14); 61 | xlim([0.5 1.05]) 62 | ylim([0 50]) 63 | 64 | elseif multi == 2 %multi constrained 65 | % calculate fixed layer constraints for Vp and density 66 | for i = 1: (num_layers-1) 67 | [val(i), idx(i)] = min(abs(x - priors.layer_depths(i))); 68 | end 69 | vp = zeros(dis,1); 70 | density = zeros(dis,1); 71 | for i = 1:num_layers 72 | if i == 1 73 | vp(1:idx(1),1) = priors.vp(1); 74 | density(1:idx(1),1) = priors.density(1); 75 | elseif i > 1 && i < num_layers 76 | vp(idx(i-1)+1:idx(i),1) = priors.vp(i); 77 | density(idx(i-1)+1:idx(i),1) = priors.density(i); 78 | else %i = num_layers 79 | vp(idx(i-1)+1:dis,1) = priors.vp(i); 80 | density(idx(i-1)+1:dis,1) = priors.density(i); 81 | end 82 | end 83 | 84 | subplot(2,3,[2 5]) 85 | plot(vp.',x,'r','LineWidth',2); %input sd vp 86 | title('P Wave Velocity PDF'); 87 | % Create ylabel 88 | ylabel('Depth (m)'); 89 | % Create xlabel 90 | xlabel('Vp (m/s)'); 91 | set(gca,'Ydir','reverse') 92 | set(gca,'fontsize',14); 93 | xlim([1500 4000]) 94 | ylim([0 50]) 95 | 96 | subplot(2,3,[3 6]) 97 | plot(density.',x,'r','LineWidth',2); %input sd density 98 | title('Density PDF'); 99 | % Create ylabel 100 | ylabel('Depth (m)'); 101 | % Create xlabel 102 | xlabel('Density (g/cc)'); 103 | set(gca,'Ydir','reverse') 104 | set(gca,'fontsize',14); 105 | xlim([0.5 1.05]) 106 | ylim([0 50]) 107 | 108 | else %multi == 3 || multi == 6 multi III and joint elastic PDFs 109 | 110 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 | % Vp plot (Normalised) 112 | subplot(2,3,[2 5]) 113 | contourf(vp_edge,depth_edge,CI_density_vp_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 114 | hold on 115 | if solution == 1 116 | plot(vp_mode_n0,x,'k','LineWidth',2); % mode solution 117 | else 118 | plot(AV_vp,x,'k','LineWidth',2); % average solution 119 | end 120 | hold on 121 | plot(priors.vpmean,x,'r','LineWidth',2); %input mean vp 122 | hold on 123 | plot((priors.vpmean+priors.vpsd),x,'g','LineWidth',2); %input sd vp 124 | hold on 125 | plot((priors.vpmean-priors.vpsd),x,'g','LineWidth',2); %input sd vp 126 | title('P Wave Velocity PDF'); 127 | % Create ylabel 128 | ylabel('Depth (m)'); 129 | % Create xlabel 130 | xlabel('Vp (m/s)'); 131 | set(gca,'Ydir','reverse') 132 | set(gca,'fontsize',14); 133 | colormap(cm) 134 | %colorbar 135 | caxis([0 0.3]) 136 | xlim([1500 4000]) 137 | ylim([0 50]) 138 | 139 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 140 | % Density plot (Normalised) 141 | subplot(2,3,[3 6]) 142 | contourf(den_edge,depth_edge,CI_density_den_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 143 | hold on 144 | if solution == 1 145 | plot(den_mode_n0,x,'k','LineWidth',2); % mode solution 146 | else 147 | plot(AV_den,x,'k','LineWidth',2); % average solution 148 | end 149 | hold on 150 | plot(priors.denmean,x,'r','LineWidth',2); %input mean denisty 151 | hold on 152 | plot((priors.denmean+priors.densd),x,'g','LineWidth',2); %input sd density 153 | hold on 154 | plot((priors.denmean-priors.densd),x,'g','LineWidth',2); %input sd density 155 | title('Density PDF'); 156 | % Create ylabel 157 | ylabel('Depth (m)'); 158 | % Create xlabel 159 | xlabel('Density (g/cc)'); 160 | set(gca,'Ydir','reverse') 161 | set(gca,'fontsize',14); 162 | colormap(cm) 163 | %colorbar 164 | caxis([0 0.3]) 165 | xlim([0.5 1.05]) 166 | ylim([0 50]) 167 | end 168 | 169 | if multi == 6 %joint elastic PDFs 170 | 171 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 172 | % Shear plot (Normalised) 173 | figure 174 | contourf(shear_edge,depth_edge,CI_density_shearN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 175 | hold on 176 | plot(shear_mode_n0,x,'k','LineWidth',2); % mode solution 177 | title('Shear PDF'); 178 | % Create ylabel 179 | ylabel('Depth (m)'); 180 | % Create xlabel 181 | xlabel('Shear modulus (10^x)'); 182 | set(gca,'Ydir','reverse') 183 | set(gca,'fontsize',14); 184 | colormap(cm) 185 | colorbar 186 | caxis([0 0.3]) 187 | %set(gca,'XScale','log') 188 | %set(gca,'XMinorTick','on') 189 | set(gca,'Ydir','reverse') 190 | xlim([5 7]) 191 | 192 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 193 | % bulk plot (Normalised) 194 | figure 195 | contourf(bulk_edge,depth_edge,CI_density_bulkN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 196 | hold on 197 | plot(bulk_mode_n0,x,'k','LineWidth',2); % mode solution 198 | title('bulk PDF'); 199 | % Create ylabel 200 | ylabel('Depth (m)'); 201 | % Create xlabel 202 | xlabel('bulk modulus (10^x)'); 203 | colormap(cm) 204 | colorbar 205 | caxis([0 0.3]) 206 | %set(gca,'XScale','log') 207 | set(gca,'Ydir','reverse') 208 | set(gca,'fontsize',14); 209 | xlim([6 7.2]) 210 | 211 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 212 | % VpVs plot (Normalised) 213 | figure 214 | contourf(VpVs_edge,depth_edge,CI_density_VpVsN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 215 | hold on 216 | plot(VpVs_mode_n0,x,'k','LineWidth',2); % mode solution 217 | title('VpVs PDF'); 218 | % Create ylabel 219 | ylabel('Depth (m)'); 220 | % Create xlabel 221 | xlabel('VpVs'); 222 | set(gca,'Ydir','reverse') 223 | set(gca,'fontsize',14); 224 | colormap(cm) 225 | colorbar 226 | caxis([0 0.3]) 227 | 228 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 229 | % PR plot (Normalised) 230 | figure 231 | contourf(PR_edge,depth_edge,CI_density_PRN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 232 | hold on 233 | plot(PR_mode_n0,x,'k','LineWidth',2); % mode solution 234 | title('Poissons ratio PDF'); 235 | % Create ylabel 236 | ylabel('Depth (m)'); 237 | % Create xlabel 238 | xlabel('Poissons ratio'); 239 | set(gca,'Ydir','reverse') 240 | set(gca,'fontsize',14); 241 | colormap(cm) 242 | colorbar 243 | caxis([0 0.3]) 244 | end 245 | 246 | 247 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 248 | %%% Plot best model modal dispersion curves and observed data 249 | if running_mode == 1 250 | %PDF ALL modes 251 | figure 252 | contourf(freq_edge,vs_edge,CI_density_ALL,1000,'edgecolor','none') %pdf plot 253 | hold on; 254 | errorbar(freq, data, fitting_error,'ok','MarkerFaceColor','k','linewidth',2) % observed data 255 | % Create ylabel 256 | ylabel('Phase velocity (m/s)'); 257 | % Create xlabel 258 | xlabel('Frequency (Hz)'); 259 | colormap(cm) 260 | colorbar 261 | set(gca,'YDir','normal') 262 | caxis([0 50000]) 263 | 264 | %PDF misfit 265 | figure 266 | contourf(freq_edge,misfit_edge,CI_density_misfit,1000,'edgecolor','none') %pdf plot 267 | hold on 268 | plot(freq, data.*0.05,'k','linewidth',4); 269 | % Create ylabel 270 | ylabel('Misfit (m/s)'); 271 | % Create xlabel 272 | xlabel('Frequency (Hz)'); 273 | colormap(cm) 274 | colorbar 275 | set(gca,'YDir','normal') 276 | caxis([0 50000]) 277 | end 278 | 279 | 280 | %%%%%%%%%%%%%%% Plot Statistics of the chain %%%%%%%%%%%%%%%% 281 | figure 282 | subplot(2,1,1) 283 | semilogy(cov); 284 | hold on 285 | %line([burn_in burn_in],[0 cov(1)],'LineWidth',4,'Color',[1 0 0]); 286 | xlabel('iterations','FontSize',14) 287 | set(gca,'fontsize',14); 288 | 289 | title('Data Misfit','FontSize',16) 290 | subplot(2,1,2); 291 | line([burn_in burn_in],[0 priors.npt_max+num_layers],'LineWidth',4,'Color',[1 0 0]); 292 | hold on 293 | plot(nnuclei) 294 | xlabel('iterations','FontSize',14) 295 | title('Number of nuclei','FontSize',16) 296 | set(gca,'fontsize',14); 297 | 298 | 299 | %%%%%%%%%%%%%% Plot Marginal posteriors %%%%%%%%%%%%%%%%%%% 300 | 301 | % Plot histogram on change points 302 | figure 303 | subplot(2,1,1) 304 | hist(change_points(1:bb),500) 305 | title('Probability of change points','FontSize',14) 306 | set(gca,'fontsize',14); 307 | 308 | % Plot histogram on number of nuclei 309 | subplot(2,1,2); 310 | bar(nnucleihist) 311 | title('Posterior Distribution on number of nuclei ','FontSize',14) 312 | set(gca,'fontsize',14); 313 | 314 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315 | -------------------------------------------------------------------------------- /tools/cmap.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/tools/cmap.mat -------------------------------------------------------------------------------- /tools/cmap_b.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eespr/MuLTI/9423cad047818a2836a146fb45f8f1678d6ea3ab/tools/cmap_b.mat -------------------------------------------------------------------------------- /tools/plotting_MuLTI_III_PDFs.m: -------------------------------------------------------------------------------- 1 | close all 2 | 3 | %load('MuLTI_III_output_data.mat') 4 | 5 | solution = 1; % 0 = average ; 1 = mode ; for Vp Vs and density plots only 6 | % the mode solution will be plotted for shear modulus, bulk modulus, Vp:Vs ratio and Poisson's ratio. 7 | 8 | load('cmap_b.mat') % load colourbar 9 | 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | % VS plot (Normalised) 12 | figure 13 | subplot(2,3,[1 4]) 14 | contourf(vs_edge,depth_edge,CI_density_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 15 | hold on 16 | if solution == 1 17 | plot(vs_mode_n0,x,'k','LineWidth',2); % mode solution 18 | else 19 | plot(AV,x,'k','LineWidth',2); % average solution 20 | end 21 | hold on 22 | plot(Vs_true,x,'r','LineWidth',2); %average solution 23 | %title('Shear Wave Velocity PDF'); 24 | % Create ylabel 25 | ylabel('Depth (m)'); 26 | % Create xlabel 27 | xlabel('Vs (m/s)'); 28 | set(gca,'Ydir','reverse') 29 | set(gca,'fontsize',10); 30 | colormap(cm) 31 | %colorbar 32 | caxis([0 0.1]) 33 | xlim([500 2500]) 34 | 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | % Vp plot (Normalised) 37 | subplot(2,3,[2 5]) 38 | contourf(vp_edge,depth_edge,CI_density_vp_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 39 | hold on 40 | if solution == 1 41 | plot(vp_mode_n0,x,'k','LineWidth',2); % mode solution 42 | else 43 | plot(AV_vp,x,'k','LineWidth',2); % average solution 44 | end 45 | hold on 46 | plot(priors.vpmean,x,'r','LineWidth',2); %input mean vp 47 | hold on 48 | plot((priors.vpmean+priors.vpsd),x,'g','LineWidth',2); %input sd vp 49 | hold on 50 | plot((priors.vpmean-priors.vpsd),x,'g','LineWidth',2); %input sd vp 51 | %title('P Wave Velocity PDF'); 52 | % Create ylabel 53 | %ylabel('Depth (m)'); 54 | % Create xlabel 55 | xlabel('Vp (m/s)'); 56 | set(gca,'Ydir','reverse') 57 | set(gca,'fontsize',10); 58 | colormap(cm) 59 | %colorbar 60 | caxis([0 0.1]) 61 | xlim([1500 4000]) 62 | ylim([0 50]) 63 | 64 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 65 | % Density plot (Normalised) 66 | subplot(2,3,[3 6]) 67 | contourf(den_edge,depth_edge,CI_density_den_limitN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 68 | hold on 69 | if solution == 1 70 | plot(den_mode_n0,x,'k','LineWidth',2); % mode solution 71 | else 72 | plot(AV_den,x,'k','LineWidth',2); % average solution 73 | end 74 | hold on 75 | plot(priors.denmean,x,'r','LineWidth',2); %input mean denisty 76 | hold on 77 | plot((priors.denmean+priors.densd),x,'g','LineWidth',2); %input sd density 78 | hold on 79 | plot((priors.denmean-priors.densd),x,'g','LineWidth',2); %input sd density 80 | %title('Density PDF'); 81 | % Create ylabel 82 | %ylabel('Depth (m)'); 83 | % Create xlabel 84 | xlabel('Density (g/cc)'); 85 | set(gca,'Ydir','reverse') 86 | set(gca,'fontsize',10); 87 | colormap(cm) 88 | %colorbar 89 | caxis([0 0.1]) 90 | xlim([0.5 1.05]) 91 | ylim([0 50]) 92 | 93 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94 | % Shear plot (Normalised) 95 | figure 96 | contourf(shear_edge,depth_edge,CI_density_shearN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 97 | hold on 98 | plot(shear_mode_n0,x,'k','LineWidth',2); % mode solution 99 | title('Shear PDF'); 100 | % Create ylabel 101 | ylabel('Depth (m)'); 102 | % Create xlabel 103 | xlabel('Shear modulus (10^x)'); 104 | set(gca,'Ydir','reverse') 105 | set(gca,'fontsize',14); 106 | colormap(cm) 107 | colorbar 108 | caxis([0 0.3]) 109 | %set(gca,'XScale','log') 110 | %set(gca,'XMinorTick','on') 111 | set(gca,'Ydir','reverse') 112 | xlim([5 7]) 113 | 114 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 115 | % bulk plot (Normalised) 116 | figure 117 | contourf(bulk_edge,depth_edge,CI_density_bulkN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 118 | hold on 119 | plot(bulk_mode_n0,x,'k','LineWidth',2); % mode solution 120 | title('bulk PDF'); 121 | % Create ylabel 122 | ylabel('Depth (m)'); 123 | % Create xlabel 124 | xlabel('bulk modulus (10^x)'); 125 | colormap(cm) 126 | colorbar 127 | caxis([0 0.3]) 128 | %set(gca,'XScale','log') 129 | set(gca,'Ydir','reverse') 130 | set(gca,'fontsize',14); 131 | xlim([6 7.2]) 132 | 133 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 134 | % VpVs plot (Normalised) 135 | figure 136 | contourf(VpVs_edge,depth_edge,CI_density_VpVsN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 137 | hold on 138 | plot(VpVs_mode_n0,x,'k','LineWidth',2); % mode solution 139 | title('VpVs PDF'); 140 | % Create ylabel 141 | ylabel('Depth (m)'); 142 | % Create xlabel 143 | xlabel('VpVs'); 144 | set(gca,'Ydir','reverse') 145 | set(gca,'fontsize',14); 146 | colormap(cm) 147 | colorbar 148 | caxis([0 0.3]) 149 | 150 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 151 | % PR plot (Normalised) 152 | figure 153 | contourf(PR_edge,depth_edge,CI_density_PRN(1:99,1:99), 1000,'edgecolor','none') %pdf plot 154 | hold on 155 | plot(PR_mode_n0,x,'k','LineWidth',2); % mode solution 156 | title('Poissons ratio PDF'); 157 | % Create ylabel 158 | ylabel('Depth (m)'); 159 | % Create xlabel 160 | xlabel('Poissons ratio'); 161 | set(gca,'Ydir','reverse') 162 | set(gca,'fontsize',14); 163 | colormap(cm) 164 | colorbar 165 | caxis([0 0.3]) 166 | 167 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 168 | %%% Plot best model modal dispersion curves and observed data 169 | if running_mode == 1 170 | %PDF ALL modes 171 | figure 172 | contourf(freq_edge,vs_edge,CI_density_ALL,1000,'edgecolor','none') %pdf plot 173 | hold on; 174 | errorbar(freq, data, fitting_error,'ok','MarkerFaceColor','k','linewidth',2) % observed data 175 | % Create ylabel 176 | ylabel('Phase velocity (m/s)'); 177 | % Create xlabel 178 | xlabel('Frequency (Hz)'); 179 | colormap(cm) 180 | colorbar 181 | set(gca,'YDir','normal') 182 | caxis([0 50000]) 183 | %PDF misfit 184 | figure 185 | contourf(freq_edge,misfit_edge,CI_density_misfit,1000,'edgecolor','none') %pdf plot 186 | hold on 187 | plot(freq, data.*0.05,'k','linewidth',4); 188 | % Create ylabel 189 | ylabel('Misfit (m/s)'); 190 | % Create xlabel 191 | xlabel('Frequency (Hz)'); 192 | colormap(cm) 193 | colorbar 194 | set(gca,'YDir','normal') 195 | caxis([0 50000]) 196 | end 197 | 198 | %%%%%%%%%%%%%%% Plot Statistics of the chain %%%%%%%%%%%%%%%% 199 | figure 200 | subplot(2,1,1) 201 | semilogy(cov); 202 | hold on 203 | %line([burn_in burn_in],[0 cov(1)],'LineWidth',4,'Color',[1 0 0]); 204 | xlabel('iterations','FontSize',14) 205 | set(gca,'fontsize',14); 206 | 207 | title('Data Misfit','FontSize',16) 208 | subplot(2,1,2); 209 | line([burn_in burn_in],[0 priors.npt_max+num_layers],'LineWidth',4,'Color',[1 0 0]); 210 | hold on 211 | plot(nnuclei) 212 | xlabel('iterations','FontSize',14) 213 | title('Number of nuclei','FontSize',16) 214 | set(gca,'fontsize',14); 215 | 216 | %%%%%%%%%%%%%% Plot Marginal posteriors %%%%%%%%%%%%%%%%%%% 217 | 218 | % Plot histogram on change points 219 | figure 220 | subplot(2,1,1) 221 | hist(change_points(1:bb),500) 222 | title('Probability of change points','FontSize',14) 223 | set(gca,'fontsize',14); 224 | 225 | % Plot histogram on number of nuclei 226 | subplot(2,1,2); 227 | bar(nnucleihist) 228 | title('Posterior Distribution on number of nuclei ','FontSize',14) 229 | set(gca,'fontsize',14); 230 | 231 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232 | --------------------------------------------------------------------------------