├── .gitignore ├── Data_Plotting ├── compare_data.m ├── edit_data.m ├── edit_data_tipper.m ├── plot_all_edi.m ├── plot_data.m ├── plot_dim_parameters.m ├── plot_impedance.m ├── plot_induction_vector_map.m ├── plot_induction_vector_site.m ├── plot_misfit_convergence.m ├── plot_misfit_cross_plot.m ├── plot_misfit_ks_test_map.m ├── plot_misfit_percent_diff_map.m ├── plot_misfit_residual_histograms.m ├── plot_misfit_residual_map.m ├── plot_misfit_residual_pseudo.m ├── plot_misfit_rms_by_period.m ├── plot_misfit_rms_by_period_map.m ├── plot_misfit_rms_by_site.m ├── plot_misfit_rms_map.m ├── plot_phase_tensor.m ├── plot_phase_tensor_beta_strike.m ├── plot_phase_tensor_ellipse_pseudo.m ├── plot_phase_tensor_map.m ├── plot_phase_tensor_pseudo.m ├── plot_polar.m ├── plot_polar_distorted.m ├── plot_polar_ellipse_pseudo.m ├── plot_polar_map.m ├── plot_rho_pha.m ├── plot_rho_pha_map.m ├── plot_rho_pha_map_det_by_site.m ├── plot_rho_pha_map_determinant.m ├── plot_rho_pha_pseudo.m ├── plot_skew_pseudo.m ├── plot_stations_map_srtm.m ├── plot_tipper.m ├── plot_tipper_angle_map.m └── plot_tipper_pseudo.m ├── Documentation ├── 000_MANUAL_MTcode.docx ├── Basic_Workflow.ai ├── Basic_Workflow.png ├── EDI_Standards │ ├── Edistd-1991.doc │ ├── Edistd.rtf │ └── ueber_edi.txt ├── Standalone_Scripts.xlsx ├── Structure_Variables.xlsx ├── Synthetic_Workflow.ai ├── Synthetic_Workflow.png ├── geoboundfiles_example.txt ├── license.txt ├── license_attributions.txt ├── mtcode_github_guide.docx └── user_defaults_master.m ├── Load_Functions ├── convert_edi_spectra_imp.m ├── convert_edi_units.m ├── link_model_data.m ├── load_covariance.m ├── load_data_2DNLCG.m ├── load_data_edi.m ├── load_data_edi_spectra.m ├── load_data_modem.m ├── load_data_wsinv.m ├── load_geoboundary_file_list.m ├── load_logfile_2DNLCG.m ├── load_logfile_modem.m ├── load_logfile_wsinv.m ├── load_model_2DNLCG.m ├── load_model_geozd.m ├── load_model_modem.m ├── load_model_ubc.m ├── load_model_wsinv.m ├── load_sitefile.m ├── load_startup_2DNLCG.m └── load_startup_wsinv.m ├── M3D ├── M3D_v1.m ├── M3D_v1_old_panels.m ├── M3_add_col.m ├── M3_add_row.m ├── M3_add_topo.m ├── M3_clear_var_in_H.m ├── M3_del_col.m ├── M3_del_row.m ├── M3_delete_layers.m ├── M3_err_flr_type_1.m ├── M3_err_flr_type_2.m ├── M3_generate_model.m ├── M3_get_srtm.m ├── M3_jump_to_layer.m ├── M3_load_mat_legacy.m ├── M3_load_mat_new.m ├── M3_load_modem_data.m ├── M3_load_modem_mod.m ├── M3_load_param.m ├── M3_load_winglink_mod.m ├── M3_load_ws_mod.m ├── M3_make_modem_cov.m ├── M3_make_param.m ├── M3_make_ws_startup.m ├── M3_max_res.m ├── M3_min_res.m ├── M3_next_layer.m ├── M3_prev_layer.m ├── M3_save_modem_data.m ├── M3_save_modem_mod.m ├── M3_save_undo.m ├── M3_save_ws_data.m ├── M3_save_ws_mod.m ├── M3_set_rot.m ├── M3_smooth_air.m ├── M3_update_model_plot.m ├── M3_view_data.m └── M3_view_model.m ├── MT_Analysis ├── Bostick │ ├── bostick1.m │ ├── bostick1_phase.m │ ├── bostick1_slope.m │ ├── bostick2.m │ ├── bostick2_phase.m │ ├── bostick2_slope.m │ ├── bostick_gridding1.m │ ├── bostick_gridding2.m │ ├── bostick_penetration.m │ ├── bostick_profile1.m │ ├── bostick_profile2.m │ └── bostick_single_station.m ├── Occam1D │ ├── Examples │ │ ├── ex3lay_con-1D-10pc_noise.dat │ │ ├── filename_occam1d.mat │ │ ├── filename_occam1d_0.05.resp │ │ ├── filename_occam1d_0.1.mod │ │ ├── filename_occam1d_data_input.mat │ │ ├── filename_occam1d_ef_10.mod │ │ ├── filename_occam1d_ef_10.resp │ │ ├── filename_occam1d_v2.mat │ │ ├── filename_occam1d_v2_data_input.mat │ │ ├── filename_occam1d_v2_ef_10.mod │ │ ├── filename_occam1d_v2_ef_10.resp │ │ └── l1_002_rho_pha_berd_av_freq.dat │ ├── OCCAM1D.m │ ├── golden_section.m │ ├── l1_002.mat │ ├── l1_002_fix.edi │ ├── mt_fwd_occ.m │ ├── plot_occam_profile.m │ └── starting_model_thickness.txt ├── Occam1D_200213.zip ├── add_noise.m ├── apply_errorfloor.m ├── calc_Z.m ├── calc_determinant.m ├── calc_dim_parameters.m ├── calc_fwd_1d.m ├── calc_pha_splits.m ├── calc_phase_tensor.m ├── calc_polar.m ├── calc_rho_pha.m ├── calc_ssq.m ├── cut_beta.m ├── dplus.m ├── dplus_detailed_statistics.m ├── dplus_plot.m ├── frequency_analysis.m ├── interpolate_edi.m ├── rotate_Z.m ├── rotate_d.m ├── rotate_tip.m └── shear_twist_anis.m ├── MTplot └── MTplot.m ├── Model_Plotting ├── add_discontinuity.m ├── compare_models.m ├── edit_block.m ├── edit_covariance.m ├── edit_model.m ├── edit_model_2d.m ├── plot_conductance.m ├── plot_cross_section.m ├── plot_cross_section_2d.m ├── plot_cross_section_3d.m ├── plot_cross_section_beneath_points.m ├── plot_cross_section_lat_long.m ├── plot_diagonal_section.m ├── plot_diagonal_section_smooth.m ├── plot_fwd_1d.m ├── plot_isosurface.m ├── plot_mesh.m ├── plot_model_3D.m ├── plot_model_topography.m ├── plot_rho_z_model.m ├── plot_rho_z_station.m ├── plot_slice.m ├── plot_slice_map.m ├── plot_slice_menus.m └── plot_slice_multi.m ├── README.md ├── S3D └── S3D_v1.m ├── Utils ├── Figures │ ├── add_rho_colorbar.m │ ├── hist2d.m │ ├── logerrorbar.m │ ├── manual_legend.m │ ├── plot_rectangular_fault_plane.m │ ├── print_figure.m │ ├── rose_geog.m │ ├── set_figure_size.m │ └── set_inset_position.m ├── Mapping │ ├── deg2utm.m │ ├── dms2deg.m │ ├── download_srtm.m │ ├── geo2utm.m │ ├── get_projection.m │ ├── grdread2.m │ ├── haversine.m │ ├── haversine_d.m │ ├── kml2geo.m │ ├── m_map │ │ ├── Contents.m │ │ ├── m_coast.m │ │ ├── m_contour.m │ │ ├── m_contourf.m │ │ ├── m_coord.m │ │ ├── m_demo.m │ │ ├── m_elev.m │ │ ├── m_etopo2.m │ │ ├── m_fdist.m │ │ ├── m_fill.m │ │ ├── m_geo2mag.m │ │ ├── m_geodesic.m │ │ ├── m_grid.m │ │ ├── m_gshhs.m │ │ ├── m_gshhs_c.m │ │ ├── m_gshhs_f.m │ │ ├── m_gshhs_h.m │ │ ├── m_gshhs_i.m │ │ ├── m_gshhs_l.m │ │ ├── m_hatch.m │ │ ├── m_idist.m │ │ ├── m_legend.m │ │ ├── m_line.m │ │ ├── m_ll2xy.m │ │ ├── m_lldist.m │ │ ├── m_mag2geo.m │ │ ├── m_patch.m │ │ ├── m_pcolor.m │ │ ├── m_plot.m │ │ ├── m_plotbndry.m │ │ ├── m_proj.m │ │ ├── m_quiver.m │ │ ├── m_range_ring.m │ │ ├── m_scale.m │ │ ├── m_tba2b.m │ │ ├── m_tbase.m │ │ ├── m_text.m │ │ ├── m_track.m │ │ ├── m_ungrid.m │ │ ├── m_usercoast.m │ │ ├── m_vec.m │ │ ├── m_xy2ll.m │ │ ├── m_xydist.m │ │ ├── map.html │ │ └── private │ │ │ ├── Thumbs.db │ │ │ ├── clabel.m │ │ │ ├── ex_modis.gif │ │ │ ├── ex_ssmi.gif │ │ │ ├── ex_sst.gif │ │ │ ├── ex_terra.gif │ │ │ ├── exgshhs.gif │ │ │ ├── exlamber.gif │ │ │ ├── exmiller.gif │ │ │ ├── exobl2.gif │ │ │ ├── exquiv.gif │ │ │ ├── exsinus.gif │ │ │ ├── exster.gif │ │ │ ├── extbase.gif │ │ │ ├── extblueocean.gif │ │ │ ├── extspeckle.gif │ │ │ ├── exvec.gif │ │ │ ├── m_coasts.mat │ │ │ ├── mapug.html │ │ │ ├── mc_coords.m │ │ │ ├── mlogo.gif │ │ │ ├── mp_azim.m │ │ │ ├── mp_conic.m │ │ │ ├── mp_cyl.m │ │ │ ├── mp_omerc.m │ │ │ ├── mp_tmerc.m │ │ │ ├── mp_utm.m │ │ │ ├── mu_coast.m │ │ │ ├── mu_util.m │ │ │ ├── new.gif │ │ │ ├── rring.gif │ │ │ ├── thumb_ex_modis.gif │ │ │ ├── thumb_ex_ssmi.gif │ │ │ ├── thumb_ex_sst.gif │ │ │ ├── thumb_ex_terra.gif │ │ │ ├── thumb_exgshhs.gif │ │ │ ├── thumb_exlamber.gif │ │ │ ├── thumb_exmiller.gif │ │ │ ├── thumb_exobl2.gif │ │ │ ├── thumb_exquiv.gif │ │ │ ├── thumb_exsinus.gif │ │ │ ├── thumb_exster.gif │ │ │ ├── thumb_extbase.gif │ │ │ ├── thumb_extblueocean.gif │ │ │ ├── thumb_extspeckle.gif │ │ │ ├── thumb_exvec.gif │ │ │ ├── thumb_mlogo.gif │ │ │ ├── thumb_rring.gif │ │ │ ├── thumb_track1.gif │ │ │ ├── track1.gif │ │ │ └── usermap.gif │ ├── plot_geoboundaries.m │ ├── plot_geoboundaries_diagonal_section.m │ ├── plot_geoboundaries_geoshow.m │ ├── plot_topo.m │ ├── profile_topo.m │ ├── read_hgt │ │ ├── dem.m │ │ ├── landcolor.m │ │ ├── license.txt │ │ ├── read_hgt.zip │ │ ├── readhgt.m │ │ ├── readhgt_srtm_index.txt │ │ └── seacolor.m │ ├── set_map_projection.m │ ├── set_map_projection_geoshow.m │ └── utm2geo.m ├── Statistics │ ├── calc_rms.m │ ├── detailed_statistics.m │ ├── detailed_statistics_2D.m │ ├── histfit.m │ ├── statistics.m │ └── strike_stats.m ├── append_d.m ├── curve_intersection.m ├── fix_pcolor.m ├── get_pseudo_section_indices.m ├── getquadrant.m ├── ginputExtra.m ├── ginput_editdata.m ├── inpaint_nans.m ├── make_nan_data.m ├── make_ones_data.m ├── make_synthetic_site_locations.m ├── mv.m ├── nearestpoint.m └── nnls.m ├── Write_Functions ├── write_data_2DNLCG.m ├── write_data_edi.m ├── write_data_modem.m ├── write_model_modem.m ├── write_model_ubc.m ├── write_model_wsinv.m ├── write_modem_covariance.m ├── write_section.m └── write_slices_cube_lat_long.m └── user_defaults.m /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | user_defaults.m 3 | user_defaults.m 4 | Utils/.DS_Store 5 | .DS_Store 6 | .DS_Store 7 | .DS_Store 8 | .DS_Store 9 | .DS_Store 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /Data_Plotting/plot_induction_vector_map.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Data_Plotting/plot_induction_vector_map.m -------------------------------------------------------------------------------- /Data_Plotting/plot_induction_vector_site.m: -------------------------------------------------------------------------------- 1 | function plot_induction_vector_site(d,is) 2 | %% 3 | % Function which plots the real and imaginary induction vectors at a given 4 | % site as a function of frequency 5 | % 6 | % Usage: plot_induction_vector_site(d,is) 7 | % 8 | % "d" is data input in standard format 9 | % "is" is the station index to plot 10 | % 11 | % The plots are in subplots 233 and 236 because this code is paired with 12 | % plot_tipper 13 | 14 | %Find real and imaginary tipper components 15 | tzxr = real(d.tip(:,2,is)); 16 | tzxi = -imag(d.tip(:,2,is)); 17 | tzyr= real(d.tip(:,1,is)); 18 | tzyi= -imag(d.tip(:,1,is)); 19 | 20 | %Real induction vector 21 | subplot(2,3,3) 22 | for ifreq=1:2:d.nf %skip every second frequency 23 | 24 | x_orig = log10(d.T(ifreq)); y_orig = 0; 25 | % Plot induction vector as a line 26 | xplot =[x_orig,x_orig+2*tzyr(ifreq)]; %x coordinate 27 | yplot =[y_orig,y_orig+2*tzxr(ifreq)]; %y coordinate 28 | plot (xplot, yplot,'b-'); hold on; 29 | plot (xplot(2),yplot(2),'b.') 30 | 31 | end 32 | title('Real Induction Vector') 33 | axis([min(log10(d.T)) max(log10(d.T)) -2 2]) 34 | xlabel('log10(Period (s))') 35 | ylabel('Real IV') 36 | grid on 37 | 38 | %Imaginary induction vector 39 | subplot(2,3,6) 40 | plot([min(log10(d.T)) max(log10(d.T))], [0 0],':k'); hold on 41 | for ifreq=1:2:d.nf 42 | x_orig = log10(d.T(ifreq)); y_orig = 0; 43 | % Plot as line 44 | xplot =[x_orig,x_orig+2*tzyi(ifreq)]; 45 | yplot =[y_orig,y_orig+2*tzxi(ifreq)]; 46 | plot (xplot, yplot,'r-'); hold on; 47 | plot (xplot(2),yplot(2),'r.') 48 | end 49 | title('Imaginary Induction Vector') 50 | axis([min(log10(d.T)) max(log10(d.T)) -2 2]) 51 | xlabel('log10(Period (s))') 52 | ylabel('Imag IV') 53 | grid on 54 | -------------------------------------------------------------------------------- /Data_Plotting/plot_misfit_convergence.m: -------------------------------------------------------------------------------- 1 | function [id1,id0,niter] = plot_misfit_convergence(invlog) 2 | %Function to plot the converange of an inversion for all iterations 3 | % 4 | % Usage: plot_misfit_convergence(invlog) 5 | % 6 | % Inputs: "invlog" is a structure variable containing iteration information 7 | % from ModEM or WSINV inversions. 8 | % 9 | % Outputs: 10 | % id1 is the iteration number of the "best trade-off" inversion (i.e. the 11 | % iteration which is nearest to an rms of 1 and a model norm of 0) 12 | % 13 | % id0 is the iteration number of the "smallest objective function" (i.e. 14 | % the iteration which is nearest to an rms of 0 and a model norm of 0. 15 | % This *should* ALWAYS be the last iteration in theory) 16 | % 17 | % niter is the total number of iterations. In general niter == id0. 18 | % 19 | %% 20 | set_figure_size(1); 21 | 22 | niter = invlog.niter; 23 | 24 | subplot(2,4,3) 25 | semilogy(invlog.lambda,'k.') 26 | title('Regularization (\lambda)') 27 | 28 | subplot(2,4,4) 29 | semilogy(invlog.alpha,'k.') 30 | title('Step Size (\alpha)') 31 | 32 | subplot(2,4,7) 33 | semilogy(invlog.m2,'k.') 34 | title('Model Norm (m2)') 35 | xlabel('Iteration Number') 36 | 37 | subplot(2,4,8) 38 | semilogy(invlog.f,'k.') 39 | title('Objective Function (f)') 40 | xlabel('Iteration Number') 41 | 42 | subplot(2,4,[1 2]) 43 | plot(invlog.rms,'k.'); hold on 44 | title('Misfit Convergence') 45 | xlabel('Iteration number') 46 | ylabel('RMS misfit') 47 | text(invlog.niter*0.75,max(invlog.rms)*0.75,['Final RMS = ',num2str(invlog.rms(invlog.niter),'%5.2f')]) 48 | 49 | %log.m2 = log.lambda.*log.m2; 50 | 51 | subplot(2,4,[5 6]) 52 | plot(invlog.rms,invlog.m2,'.k'); hold on 53 | xlabel('RMS Misfit') 54 | ylabel('Model Norm') 55 | %axis equal 56 | if ~isnan(invlog.m2) 57 | axis([0 max(invlog.rms)*1.5 0 max(invlog.m2)*1.5]) 58 | end 59 | 60 | d0 = sqrt((invlog.rms).^2+(invlog.m2).^2); 61 | [~,id0] = min(d0); 62 | 63 | d1 = sqrt((invlog.rms-1).^2+(invlog.m2).^2); 64 | [~,id1] = min(d1); 65 | 66 | %plot([0 invlog.rms(id0)],[0 invlog.m2(id0)],'--b') 67 | %plot([1 invlog.rms(id1)],[0 invlog.m2(id1)],'--b') 68 | %plot(invlog.rms(id1),invlog.m2(id1),'*r') 69 | %text(max(invlog.rms)*0.75,max(invlog.m2)*0.75,['"Best" Iteration = #',num2str(id1),'. (RMS = ',num2str(invlog.rms(id1)),')']); 70 | 71 | title('"L Curve"') 72 | 73 | annotation('textbox', [0 0.9 1 0.08], ... 74 | 'String', ['Total Number of Iterations: ',num2str(invlog.niter)], ... 75 | 'EdgeColor', 'none', ... 76 | 'HorizontalAlignment', 'center','FontSize',12,'FontWeight','bold') 77 | -------------------------------------------------------------------------------- /Data_Plotting/plot_misfit_rms_by_site.m: -------------------------------------------------------------------------------- 1 | function plot_misfit_rms_by_site(dobs,dpred,is,s) 2 | % Function which plots rms misfit for two MT datasets for all sites as well 3 | % as a highlighted site specified by "is". 4 | % Site rms is plotted as a function of site number 5 | % 6 | % Usage: plot_misfit_rms_by_site(dobs,dpred) OR plot_rms_by_site(dobs,dpred,is) 7 | % 8 | % "dobs" is observed MT data structure 9 | % "dpred" is predicted MT data structure (no longer required since s is an 10 | % input) 11 | % "s" is a stats structure containing data misfit 12 | % "is" is an OPTIONAL input to highlight a specific site index 13 | % 14 | % 15 | %Note: This function is usually only called by other functions (see plot_data.m) 16 | % It is usually placed in the lower right subplot of the currently open 17 | % figure (2x2 or 2x3 subplots of data plots) 18 | % 19 | 20 | 21 | 22 | %Get detailed statistics and rms by site 23 | % [all_stats,rms_site,~,~,~,~,~] = detailed_statistics(dobs,dpred); 24 | 25 | if length(findobj(gcf,'type','axes')) > 4 %If diagonals exist plot in the 6th subplot position 26 | subplot(2,3,6) 27 | elseif length(findobj(gcf,'type','axes')) == 3 || length(findobj(gcf,'type','axes')) == 4 %If diagonals do not exist, plot in the 4th subplot location 28 | subplot(2,2,4) 29 | else %Otherwise just plot normally 30 | close all 31 | subplot(1,1,1) 32 | end 33 | 34 | if ~exist('s','var') 35 | s = detailed_statistics(dobs,dpred); 36 | end 37 | 38 | % title('RMS Error Plot'); hold on 39 | plot(s.rms_site,'*k'); hold on 40 | if exist('is','var') 41 | plot(is,s.rms_site(is),'*r','MarkerSize',12); 42 | end 43 | plot([0,dobs.ns+1],[s.rms, s.rms],'-r') 44 | xlabel('Site Number') 45 | ylabel('Overall Root Mean Square Misfit') 46 | axis([0 dobs.ns+1 0 max(s.rms_site)+1]) 47 | title(['Overall RMS = ', num2str(s.rms,'%.2f'),'. IMP RMS = ',num2str(s.rms_imp,'%.2f'),'. TIP RMS = ',num2str(s.rms_tip,'%.2f')]) 48 | box on 49 | 50 | if exist('is','var') 51 | annotation('textbox', [0 0.9 1 0.08], ... 52 | 'String', strrep(['Compare Responses at Site ',num2str(is,'%03.0f'),': ',dobs.site{is},', R.M.S. = ',num2str(s.rms_site(is),'%.2f')],'_','\_'), ... 53 | 'EdgeColor', 'none', ... 54 | 'HorizontalAlignment', 'center','FontSize',12,'FontWeight','bold') 55 | end 56 | 57 | 58 | 59 | end -------------------------------------------------------------------------------- /Data_Plotting/plot_polar.m: -------------------------------------------------------------------------------- 1 | function plot_polar(d,polar,is) 2 | %% 3 | % Function to plot polar diagram for a single site at 9 different periods 4 | % pre-determined by the data 5 | % 6 | % Usage: plot_polar(d,polar,is) 7 | % 8 | % "d" is MT data structure 9 | % "polar" is a structure of polar diagram variables 10 | % See calc_polar function 11 | % "is" is site index 12 | % 13 | rot_ang = 0; 14 | 15 | set_figure_size(100); 16 | 17 | %Determine the 9 periods which will be plotted 18 | [~, T_first] = max(~isnan(d.Z(:,2,:)), [], 1); %First non-NaN period 19 | T_first = min(T_first); 20 | 21 | [~, T_last] = max(flipud(~isnan(d.Z(:,2,:))), [], 1); %Last non-NaN period 22 | T_last = d.nf-min(T_last); 23 | 24 | n = 1; 25 | for ifreq = floor(linspace(T_first,T_last,9)) %Loop over 9 periods 26 | 27 | ifreq = min(length(d.T),ifreq+2); 28 | subplot(3,3,n) %Will output a 3 x 3 subplot 29 | 30 | %Normalized polar diagram radius 31 | r = 1.1*max([squeeze(abs(polar.x(ifreq,2,is,:))); squeeze(abs(polar.y(ifreq,2,is,:)))]); 32 | 33 | % Plot whole ellipse 34 | plot(squeeze(polar.y(ifreq,2,is,:)),squeeze(polar.x(ifreq,2,is,:)),'k-') % Off-diagonal 35 | hold on 36 | plot(squeeze(polar.y(ifreq,1,is,:)),squeeze(polar.x(ifreq,1,is,:)),'k:') % Diagonal 37 | axis equal 38 | 39 | % Now plot axis showing coordinate frame 40 | xc1 = [0, r*cos(rot_ang*pi/180.)]; yc1 = [0, r*sin(rot_ang*pi/180.)] ; 41 | xc2 = [0, r*cos(pi/2+rot_ang*pi/180.)]; yc2 = [0, r*sin(pi/2+rot_ang*pi/180.)]; 42 | plot(yc1,xc1,'r-'); plot(yc2,xc2,'b-'); 43 | if ~isnan(r) 44 | axis([-r r -r r]); 45 | axis equal 46 | title(['T = ',num2str(d.T(ifreq)),' s']) 47 | else % if there is no data at this period 48 | title(['No Data for T = ',num2str(d.T(ifreq)),' s']) 49 | end 50 | 51 | n=n+1; 52 | end 53 | 54 | annotation('textbox', [0 0.92 1 0.08], ... 55 | 'String', ['Polar Diagram For Site ',d.site{is}], ... 56 | 'EdgeColor', 'none', ... 57 | 'HorizontalAlignment', 'center','FontSize',12,'FontWeight','bold') 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Data_Plotting/plot_polar_map.m: -------------------------------------------------------------------------------- 1 | function plot_polar_map(d,polar) 2 | %% 3 | % Function to plot polar diagrams for all stations in map view as a 4 | % function of period 5 | % 6 | % Usage: plot_polar_map(d,polar) 7 | % 8 | % "d" is MT data structure 9 | % "polar" is a structure of polar diagram variables 10 | % See calc_polar function 11 | % 12 | 13 | u = user_defaults; 14 | [L] = load_geoboundary_file_list; 15 | [d] = set_map_projection(d); 16 | 17 | % Convert station locations from lat/long to UTM 18 | centlong=(max(d.loc(:,2))-min(d.loc(:,2)) )/2 + min(d.loc(:,2)); 19 | centlat=(max(d.loc(:,1))-min(d.loc(:,1)) )/2 + min(d.loc(:,1)); 20 | [loc_ew,loc_ns]=geo2utm(d.loc(:,2),d.loc(:,1),centlong,centlat); 21 | 22 | %======================================================================== 23 | % Plot results for all stations on map 24 | %======================================================================== 25 | 26 | for ifreq = 1:u.nskip:d.nf % Loop over frequencies 27 | 28 | set_figure_size(1); 29 | m_grid('box','fancy','tickdir','in','xlabeldir','end'); 30 | hold on 31 | for is = 1:u.sskip:d.ns % Loop over stations 32 | 33 | %Normalized polar diagram radius 34 | r = 1.1*max([squeeze(abs(polar.x(ifreq,2,is,:))); squeeze(abs(polar.y(ifreq,2,is,:)))]); 35 | scale = u.phase_tensor_polar_scale/r; 36 | 37 | %Convert station locations (e.g. center of ellipse) to lat long 38 | [long_cent,lat_cent]=utm2geo(loc_ew(is),loc_ns(is),centlong,centlat); 39 | m_plot(long_cent,lat_cent,'.k') 40 | 41 | % Plot off-diagonal peanut 42 | [polar1,polar2]=utm2geo(squeeze(loc_ew(is)+scale*polar.y(ifreq,2,is,:)),... 43 | squeeze(loc_ns(is)+scale*polar.x(ifreq,2,is,:)),centlong,centlat); 44 | m_plot(polar1,polar2,'k-') 45 | 46 | % Plot diagonal peanut 47 | [polar1,polar2]=utm2geo(squeeze(loc_ew(is)+scale*polar.y(ifreq,1,is,:)),... 48 | squeeze(loc_ns(is)+scale*polar.x(ifreq,1,is,:)),centlong,centlat); 49 | m_plot(polar1,polar2,'r-') 50 | 51 | end 52 | 53 | plot_topo(d,3); 54 | plot_geoboundaries(L); 55 | 56 | if d.T(ifreq) > 1; 57 | title(['T = ',num2str(d.T(ifreq)),' s']) 58 | else 59 | title(['f = ',num2str(1/d.T(ifreq)),' Hz']) 60 | end 61 | 62 | xlabel('Longitude') 63 | ylabel('Latitude') 64 | 65 | print_figure('polar',['polar_map_',num2str(ifreq,'%03.0f'),'_',num2str(d.T(ifreq))]); %Save figure 66 | 67 | 68 | pause(0.1) 69 | 70 | end 71 | 72 | end 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Data_Plotting/plot_tipper.m: -------------------------------------------------------------------------------- 1 | function plot_tipper(d,is,flag) 2 | % 3 | % Function which plots tipper for a single station 4 | % 5 | % Usage: plot_tipper(d,is,flag) 6 | % 7 | % "d" is an MT data structure 8 | % "is" is the index of the station to plot (note: if "d" only includes one 9 | % station then is must equal 1) 10 | % "flag" is an OPTIONAL input 1 or 0 to set different subplot settings (0 is default) 11 | % 12 | % The function will plot a 2 x 2 set of subplots which includes real and 13 | % imaginary Tx and Ty as well as a map indicating which station is plotted. The 14 | % bottom right subplot is left intentionally blank and is sometimes used to 15 | % plot other relevant things (e.g. rms) 16 | 17 | if ~exist('flag','var') 18 | flag = 0; 19 | end 20 | 21 | u = user_defaults; 22 | 23 | if ~all(isnan(d.tip(:))) %If the entire tipper array is NaN, then no tipper data exists and do not plot anything 24 | 25 | 26 | if isnan(d.tiperr) %If all error is NaN then we are looking at predicted data and it will be plotted as a line 27 | linetype = {'-r','-b','-m','-g'}; 28 | else %If errors exist then we have observed data which will be plotted as points 29 | linetype = {'or','sb','om','sg'}; 30 | end 31 | 32 | %Plot real tipper components 33 | if flag 34 | subplot(2,3,3) 35 | else 36 | subplot(2,2,1) 37 | end 38 | errorbar(d.T,real(d.tip(:,1,is)),real(d.tiperr(:,1,is)),linetype{1});hold on 39 | errorbar(d.T,real(d.tip(:,2,is)),real(d.tiperr(:,2,is)),linetype{2}); 40 | axis([u.Tlim(1) u.Tlim(2) u.tiplim(1) u.tiplim(2)]) 41 | set(gca,'XScale','log') 42 | ylabel('Real Tipper') 43 | xlabel('Period (s)'); 44 | grid on 45 | title(['Station ',num2str(is),' out of ',num2str(d.ns),': ',char(d.site(is))],'Interpreter','none'); 46 | h = zeros(2, 1); 47 | h(1) = plot(NaN,NaN,linetype{1}); 48 | h(2) = plot(NaN,NaN,linetype{2}); 49 | legend(h, 'Tx','Ty'); 50 | 51 | %Plot imaginary tipper components 52 | if flag 53 | subplot(2,3,6) 54 | else 55 | subplot(2,2,3) 56 | end 57 | errorbar(d.T,imag(d.tip(:,1,is)),imag(d.tiperr(:,1,is)),linetype{1}); hold on 58 | errorbar(d.T,imag(d.tip(:,2,is)),imag(d.tiperr(:,2,is)),linetype{2}); 59 | set(gca,'XScale','log') 60 | axis([u.Tlim(1) u.Tlim(2) u.tiplim(1) u.tiplim(2)]) 61 | ylabel('Imaginary Tipper') 62 | xlabel('Period (s)') 63 | grid on 64 | else 65 | disp('No Tipper data in your observed data!') 66 | end 67 | 68 | 69 | end 70 | -------------------------------------------------------------------------------- /Documentation/000_MANUAL_MTcode.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/000_MANUAL_MTcode.docx -------------------------------------------------------------------------------- /Documentation/Basic_Workflow.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Basic_Workflow.ai -------------------------------------------------------------------------------- /Documentation/Basic_Workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Basic_Workflow.png -------------------------------------------------------------------------------- /Documentation/EDI_Standards/Edistd-1991.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/EDI_Standards/Edistd-1991.doc -------------------------------------------------------------------------------- /Documentation/Standalone_Scripts.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Standalone_Scripts.xlsx -------------------------------------------------------------------------------- /Documentation/Structure_Variables.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Structure_Variables.xlsx -------------------------------------------------------------------------------- /Documentation/Synthetic_Workflow.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Synthetic_Workflow.ai -------------------------------------------------------------------------------- /Documentation/Synthetic_Workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/Synthetic_Workflow.png -------------------------------------------------------------------------------- /Documentation/geoboundfiles_example.txt: -------------------------------------------------------------------------------- 1 | Lakes_Map.txt, fill, -k, 1, b, 0.5 2 | Seismicity_All.txt, marker, b., 4 3 | 4 | # 5 | Put other files after the "#" if you don't want to plot them 6 | 7 | 8 | This text file contains a list of two other text files: Lakes_Map and Seismicity_All (any files in the list must be on your MATLAB path) 9 | 10 | This first file contains longitude and latitude coordinates for the outline of some lakes in the study area. These will be plotted as a black 11 | line as shown by the line specifier (-k) with a line width of 1, a fill color of blue, and facealpha (transparency) of 0.5. 12 | 13 | The second file contains longitude, latitude and elevation coordinates for earthquake epicenters in the study area. These will be plotted as blue 14 | dots as shown by the color and marker specifier (b.) with a marker size of 4. 15 | 16 | After the list, there is a # and the file will not be read after this point, so you can add comments or whatever you want after that point. 17 | 18 | # each file must contain only lines, markers, or filled polygons 19 | # polygons should start and end at the same point 20 | # the plotting style will be the same for every object in a particular file 21 | 22 | # Valid entries: 23 | 24 | for Markers: 25 | filename, type 26 | filename, type, color+marker, markersize 27 | 28 | for Lines: 29 | filename, type 30 | filename, type, linestyle+color, linewidth 31 | filename, type, linestyle+color+marker, linewidth, markersize 32 | 33 | for Fills: 34 | filename, type 35 | filename, type, linestyle+color, linewidth, facecolor, facealpha 36 | 37 | # General Examples 38 | 39 | for Markers: 40 | points.txt, marker 41 | points.txt, marker, kd, 12 42 | 43 | for Lines: * note for lines you can specify a linestyle AND a marker * 44 | lines.txt, line 45 | lines.txt, line, --k, 2 46 | lines.txt, line, -.ko, 2, 8 47 | 48 | for Fills: 49 | polygons.txt, fill 50 | polygons.txt, fill, -k, 2, b, 0.5 51 | -------------------------------------------------------------------------------- /Documentation/license_attributions.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/license_attributions.txt -------------------------------------------------------------------------------- /Documentation/mtcode_github_guide.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Documentation/mtcode_github_guide.docx -------------------------------------------------------------------------------- /Load_Functions/convert_edi_spectra_imp.m: -------------------------------------------------------------------------------- 1 | function convert_edi_spectra_imp 2 | % 3 | % If loading spectra EDI file, use load_data_edi_spectra.m 4 | 5 | % Function which converts EDI files from Phoenix spectra format to impedance format 6 | % Calls routine readEDI_spectra.m provided by Christina Walter 7 | % All EDI files in folder are converted and placed in new folder edi_imp 8 | % July 31 2016 : Compared to conversion in Winglink and results agree 9 | 10 | % Still needed : (a) error calculation 11 | % (b) Check if results below are for remote reference or ocal processing, since 12 | % both are possible. 13 | % 14 | % 15 | 16 | clear all; close all; 17 | 18 | % X =1 Y = 2 19 | cf = 1.25660E-03; % 4*pi*1e-4 20 | 21 | mkdir edi_imp 22 | 23 | % List all *.edi files in folder 24 | d=dir; 25 | fff=length(d); 26 | count=1; 27 | for iio=1:fff 28 | [pathstr, name, ext] = fileparts(d(iio).name); 29 | if strcmp(ext,'.edi') 30 | edst{count}=d(iio).name; 31 | count=count+1; 32 | else 33 | disp([d(iio).name,' is not an edi file']); 34 | end 35 | end 36 | 37 | coord = []; pers = []; nsta=length(edst); 38 | 39 | % Loop over all EDI files 40 | for is=1:nsta 41 | 42 | disp(['Reading ',edst{is}]) 43 | [header,freq,imp_ten,tip_comp] = readEDI_spectra(edst{is}); 44 | 45 | nfreq = length(freq); 46 | lat = header.lat; long = header.lon; elev = header.elev; 47 | filename = header.name; 48 | 49 | % Reformat 50 | for ifreq = 1:nfreq 51 | Z(1,1,ifreq) =cf*complex(imp_ten(ifreq,1),imp_ten(ifreq,2)); 52 | Z(1,2,ifreq) =cf*complex(imp_ten(ifreq,3),imp_ten(ifreq,4)); 53 | Z(2,1,ifreq) =cf*complex(imp_ten(ifreq,5),imp_ten(ifreq,6)); 54 | Z(2,2,ifreq) =cf*complex(imp_ten(ifreq,7),imp_ten(ifreq,8)); 55 | Zvar(1,1,ifreq) = 0.01; Zvar(1,2,ifreq) = 0.01; 56 | Zvar(2,1,ifreq) = 0.01; Zvar(2,2,ifreq) = 0.01; 57 | 58 | T(1,ifreq) = complex(tip_comp(ifreq,1),tip_comp(ifreq,2)); 59 | T(2,ifreq) = complex(tip_comp(ifreq,3),tip_comp(ifreq,4)); 60 | Tvar(1,ifreq) = 0.01; Tvar(2,ifreq) = 0.01; 61 | 62 | zrot(ifreq) = 0.; trot(ifreq) = 0.; rhorot(ifreq) = 0.; 63 | 64 | end 65 | 66 | n22 = NaN(2,2,nfreq); 67 | 68 | % Write in impedance format 69 | write_edi_imp(Z,Zvar,n22,n22,n22,n22,T,Tvar,freq,lat,long,elev,zrot,rhorot,trot,['edi_imp/',edst{is}]) 70 | 71 | end -------------------------------------------------------------------------------- /Load_Functions/convert_edi_units.m: -------------------------------------------------------------------------------- 1 | function convert_edi_units(filename) 2 | % 3 | % Function to convert EDI file from SI units to field units. 4 | % 5 | % Usage: convert_edi_units(filename) 6 | % 7 | % Inputs: filename is the EDI file in SI units 8 | % 9 | % Outputs: Saves an EDI file in field units with filename_converted name 10 | % 11 | % 12 | % All MTcode scripts assume an EDI file is in field units. If an EDI file is 13 | % in SI units, then the EDI should be converted to field units before using 14 | % "load_data_edi", "interpolate_edi", "MTplot" and other MTcode scripts. 15 | % 16 | % Impedance field units = E/B. E is in mV/km and B is in nT 17 | % 18 | % Impedance SI units = E/H. E is in V/m and H is in A/m 19 | % 20 | % To convert: Z_field = (Z_SI)/(mu*1000) 21 | % 22 | % 23 | 24 | 25 | 26 | mu = 4*pi*10^-7; 27 | 28 | [d] = load_data_edi(filename); 29 | 30 | d.Z = d.Z/(mu*1000); 31 | d.Zerr = d.Zerr/(mu*1000); 32 | [d.rho,d.pha,d.rhoerr,d.phaerr]=calc_rho_pha(d.Z,d.Zerr,d.T); % calculate from the converted impedance 33 | 34 | d.site = {[d.site{1},'_converted']}; 35 | 36 | disp(['Converting Site ',d.site{1},' from SI units to Field Units']) 37 | 38 | if nanmedian(d.rho(:,2:3,:))<1 %If, after doing the conversion, the resistivies are still very small then something very strange is going on 39 | disp(['AFTER UNIT CONVERSION: Site ', filename(1:end-4),' STILL HAS VERY LOW RESISTIVITES (MEDIAN <1 OHM M). Please assess EDI file.']) 40 | elseif nanmedian(d.rho(:,2:3,:))>10^6 %If after doing the conversion, the resistivites are huge then something else is very wrong. (Possibly the EDI file was already in field units?) 41 | disp(['AFTER UNIT CONVERSION: Site ', filename(1:end-4),' HAS VERY HIGH RESISTIVITES (MEDIAN >10^6 OHM M). Please assess EDI file.']) 42 | else 43 | disp(['AFTER UNIT CONVERSION: Site ', filename(1:end-4),' has realistic resistivity values (Median = ',nanmedian(nanmedian(d.rho(:,2:3,:))),' Ohm m)']) 44 | end 45 | 46 | write_data_edi(d,1); 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Load_Functions/load_covariance.m: -------------------------------------------------------------------------------- 1 | function C = load_covariance(filename,model_filename) 2 | %Function which loads a given ModEM covariance file and places it within a 3 | %standard model structure format where A is the covariance mask integers. 4 | % 5 | % Inputs: 6 | % filename - The ModEM covariance filename 7 | % model_filename - The corresponding model filename associated with the 8 | % covariance 9 | % 10 | % Outputs: 11 | % C - A standard model structure which contains all the info such that 12 | % the covariance masks can be plotted using standard functions such as 13 | % plot_slice 14 | % The C structure also contains additional info about the covariance 15 | % parameters stored in the cov_params variable. 16 | 17 | m = load_model_modem(model_filename); 18 | 19 | fid = fopen(filename); 20 | 21 | line = fgetl(fid); 22 | 23 | %Read header 24 | while line(1) == '+' || line(1) == '#' || line(1) == '|' 25 | line = fgetl(fid); 26 | if isempty(line) 27 | line = fgetl(fid); 28 | end 29 | end 30 | 31 | dim = str2num(line); 32 | nx = dim(1); ny = dim(2); nz = dim(3); 33 | 34 | line = fgetl(fid); 35 | 36 | cov_params.covx = fscanf(fid,'%f',nz); 37 | cov_params.covy = fscanf(fid,'%f',nz); 38 | cov_params.covz = fscanf(fid,'%f',1); 39 | 40 | cov_params.num_times_smoothing_applied = fscanf(fid,'%i',1); 41 | cov_params.num_exceptions = fscanf(fid,'%i',1); 42 | 43 | while ~strcmp(line,'1 1') 44 | line = fgetl(fid); 45 | end 46 | 47 | A = zeros(nx,ny,nz); 48 | for i = 1:nz 49 | block = fscanf(fid,'%i',nx*ny); 50 | block = flipud(block); 51 | A(:,:,i) = reshape(block,ny,nx)'; 52 | A(:,:,i) = A(:,end:-1:1,i); 53 | line = fscanf(fid,'%i',2); 54 | end 55 | 56 | fclose(fid); 57 | 58 | 59 | A(A==0) = NaN; 60 | 61 | if nx==m.nx && ny==m.ny && nz==m.nz && isequal(size(A), size(m.A)) || (isvector(A) && isvector(m.A) && numel(A) == numel(m.A)) 62 | C = m; 63 | C.A = A; 64 | C.cov_params = cov_params; 65 | else 66 | error('The size of the covariance model space is not the same as your input model space. Check file inputs'); 67 | end 68 | -------------------------------------------------------------------------------- /Load_Functions/load_logfile_2DNLCG.m: -------------------------------------------------------------------------------- 1 | function [log] = load_logfile_2DNLCG(logfile) 2 | % 3 | % Function which loads a ModEM *.log file output from the inversion 4 | % 5 | % Usage: [log] = load_logfile_modem(logfile) 6 | % 7 | % "log" is a structure containing data fit and model norm info for each iteration 8 | % "logfile" is the ModEM log file name string 9 | % 10 | 11 | fid=fopen(logfile,'r'); 12 | 13 | disp('Loading 2DNLCG Log file') 14 | 15 | line = fgetl(fid); 16 | 17 | while ~strcmp(line(2:6),'iter ') 18 | line = fgetl(fid); 19 | end 20 | 21 | i = 1; num = []; 22 | while 1 23 | line = fgetl(fid); 24 | if line ~= -1 25 | num(i,:) = str2num(line); 26 | if any(isinf(num(i,:))) 27 | f = strfind(line,'E'); 28 | line = [line(1:f(1)+3),' ',line(f(1)+4:end)]; 29 | num(i,:) = str2num(line); 30 | end 31 | i = i+1; 32 | else 33 | break 34 | end 35 | 36 | end 37 | 38 | N = length(num(:,1)); 39 | log.f = num(:,7); 40 | log.m2 = nan(N,1); 41 | log.rms = num(:,3); 42 | log.lambda = nan(N,1); 43 | log.alpha = nan(N,1); 44 | log.niter = N; 45 | 46 | end 47 | -------------------------------------------------------------------------------- /Load_Functions/load_logfile_wsinv.m: -------------------------------------------------------------------------------- 1 | function [log] = load_logfile_wsinv(logfile) 2 | % 3 | % Function which loads a WSINV3D *.log file output from the inversion 4 | % 5 | % Usage: [log] = load_logfile_wsinv(logfile) 6 | % 7 | % "log" is a structure containing data fit and model norm info for each iteration 8 | % "logfile" is the ModEM log file name string 9 | % 10 | 11 | fid=fopen(logfile,'r'); 12 | 13 | disp('Loading WSINV Log file') 14 | 15 | i=1; 16 | while 1 17 | 18 | line=fgetl(fid); 19 | if length(line)>11 20 | if strcmp(line(1:11),'<<< ITER NO') 21 | line(strfind(line,'=')) = []; 22 | key = 'RMS'; 23 | idx = strfind(line,key); 24 | log.rms(i) = sscanf(line(idx(1)+length(key):end),'%g',1); 25 | 26 | key = 'LM'; 27 | idx = strfind(line,key); 28 | log.m2(i) = sscanf(line(idx(1)+length(key):end),'%g',1); 29 | 30 | i=i+1; 31 | 32 | 33 | end 34 | end 35 | 36 | if line == -1 37 | break 38 | end 39 | 40 | end 41 | 42 | log.niter = length(log.rms); 43 | 44 | %These variables do not exist in the WSINV logfile and are set to NaN. They 45 | %only exist in the ModEM inversion logfile. 46 | log.f = nan(log.niter,1); 47 | log.lambda = nan(log.niter,1); 48 | log.alpha = nan(log.niter,1); 49 | 50 | end 51 | %==================================================================== -------------------------------------------------------------------------------- /Load_Functions/load_sitefile.m: -------------------------------------------------------------------------------- 1 | function [site,locxy,ref] = load_sitefile(name,ns) 2 | %Function which loads the site names from the *.stn file from a 2D NLCG 3 | %Inversion 4 | % 5 | % Usage: [site,locxy,ref] = load_sitefile(name,ns) 6 | 7 | fid=fopen(name,'r'); 8 | 9 | fgetl(fid); 10 | ref = str2double(fgetl(fid)); 11 | 12 | i=1; 13 | site{ns} = []; locxy = ones(ns,3); 14 | 15 | while 1 16 | 17 | line = fgetl(fid); 18 | 19 | if line~=-1 20 | site{i} = line(1:find(line==';')-1); 21 | 22 | locxy(i,2) = str2double(line(find(line==';')+1:end)); % *1000; think it's already in m 23 | 24 | i=i+1; 25 | else 26 | break 27 | end 28 | 29 | 30 | end 31 | 32 | end -------------------------------------------------------------------------------- /Load_Functions/load_startup_wsinv.m: -------------------------------------------------------------------------------- 1 | function [invtype, dobs_file, Z_err_floor, tip_err_floor, logfile, m0_file] = load_startup_wsinv(startupfile) 2 | 3 | fid = fopen(startupfile,'r'); 4 | tmp=0; 5 | Z_err_floor = 0; 6 | tip_err_floor = 0; 7 | 8 | while isempty(tmp)~=1 9 | tmp = fscanf(fid,'%s',1); % reading 10 | if strcmp(tmp,'INVERSION_TYPE') 11 | invtype = str2double(fscanf(fid,'%s',1)); 12 | elseif strcmp(tmp,'DATA_FILE') 13 | dobs_file = fscanf(fid,'%s',1); 14 | elseif strcmp(tmp,'MIN_ERROR_Z') 15 | Z_err_floor = str2double(fscanf(fid,'%s',1)); 16 | elseif strcmp(tmp,'MIN_ERROR_T') 17 | tip_err_floor = str2double(fscanf(fid,'%s',1)); 18 | 19 | elseif strcmp(tmp,'OUTPUT_FILE') 20 | logfile = [fscanf(fid,'%s',1),'.log']; 21 | elseif strcmp(tmp,'INITIAL_MODEL_FILE') 22 | m0_file = fscanf(fid,'%s',1); 23 | end 24 | end 25 | 26 | 27 | end -------------------------------------------------------------------------------- /M3D/M3_add_col.m: -------------------------------------------------------------------------------- 1 | function M3_add_col(hObject,eventdata,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | return 8 | end 9 | 10 | newXLim = get(H.axes1,'XLim'); 11 | newYLim = get(H.axes1,'YLim'); 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | while 1 16 | [za,~,zc]=ginput(1); 17 | if zc==3 18 | break 19 | end 20 | za=round(za*1000)/1000;minza=min(abs(abs(H.YY)-abs(za))); 21 | if minza<1 %minimum mesh spacing is 1km 22 | button = questdlg('Columns are too close! Do you want to add anyways?','Are you sure','Yes','No','Yes'); 23 | switch button 24 | case 'No' 25 | return 26 | end 27 | end 28 | [yut, ~]=size(H.YY); 29 | if yut>1 30 | H.YY=sort([H.YY;za]); 31 | else 32 | H.YY=sort([H.YY,za]); 33 | end 34 | lk=find(H.YY==za); 35 | H.nx=length(H.XX); H.ny=length(H.YY); 36 | if isfield(H,'AAt') 37 | ab(:,1:lk,:)=H.AAt(:,1:lk,:); 38 | ab(:,lk+1,:)=H.AAt(:,lk,:); 39 | ab(:,lk+2:H.ny,:)=H.AAt(:,lk+1:H.ny-1,:); 40 | H.AAt=ab; 41 | else 42 | ab(:,1:lk,:)=H.AA(:,1:lk,:); 43 | ab(:,lk+1,:)=H.AA(:,lk,:); 44 | ab(:,lk+2:H.ny,:)=H.AA(:,lk+1:H.ny-1,:); 45 | H.AA=ab; 46 | end 47 | M3_update_model_plot(H) 48 | set(H.axes1,'XLim',newXLim) 49 | set(H.axes1,'YLim',newYLim) 50 | end 51 | 52 | M3_update_model_plot(H) 53 | 54 | if ~isfield(H,'undo') 55 | H.undo=0; 56 | end 57 | H.undo=H.undo+1; 58 | 59 | % M3_save_undo(hObject, eventdata, H) 60 | 61 | guidata(hObject, H) 62 | 63 | end % end add_col_Callback -------------------------------------------------------------------------------- /M3D/M3_add_row.m: -------------------------------------------------------------------------------- 1 | function M3_add_row(hObject,eventdata,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | return 8 | end 9 | 10 | newXLim = get(H.axes1,'XLim'); 11 | newYLim = get(H.axes1,'YLim'); 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | while 1 16 | [~,zb,zc]=ginput(1); 17 | if zc==3 18 | break 19 | end 20 | zb=round(zb*1000)/1000;minza=min(abs(abs(H.XX)-abs(zb))); 21 | if minza<1 %minimum mesh spacing is 1km 22 | button = questdlg('Columns are too close! Do you want to add anyways?','Are you sure','Yes','No','Yes'); 23 | switch button 24 | case 'No' 25 | return 26 | end 27 | end 28 | [yut, ~]=size(H.XX); 29 | if yut>1 30 | H.XX=sort([H.XX;zb]); 31 | else 32 | H.XX=sort([H.XX,zb]); 33 | end 34 | lk=find(H.XX==zb); 35 | H.nx=length(H.XX); H.ny=length(H.YY); 36 | if isfield(H,'AAt') 37 | ab(1:lk,:,:)=H.AAt(1:lk,:,:); 38 | ab(lk+1,:,:)=H.AAt(lk,:,:); 39 | ab(lk+2:H.nx,:,:)=H.AAt(lk+1:H.nx-1,:,:); 40 | H.AAt=ab; 41 | else 42 | ab(1:lk,:,:)=H.AA(1:lk,:,:); 43 | ab(lk+1,:,:)=H.AA(lk,:,:); 44 | ab(lk+2:H.nx,:,:)=H.AA(lk+1:H.nx-1,:,:); 45 | H.AA=ab; 46 | end 47 | M3_update_model_plot(H) 48 | set(H.axes1,'XLim',newXLim) 49 | set(H.axes1,'YLim',newYLim) 50 | end 51 | 52 | M3_update_model_plot(H) 53 | 54 | if ~isfield(H,'undo') 55 | H.undo=0; 56 | end 57 | H.undo=H.undo+1; 58 | 59 | % M3_save_undo(hObject, eventdata, H) 60 | 61 | guidata(hObject, H) 62 | 63 | end % end add_row_Callback -------------------------------------------------------------------------------- /M3D/M3_clear_var_in_H.m: -------------------------------------------------------------------------------- 1 | function clear_variables_in_H(hObject,H) 2 | 3 | if isfield(H,'x') 4 | H = rmfield ( H,'x'); 5 | end 6 | if isfield(H,'y') 7 | H = rmfield ( H,'y'); 8 | end 9 | if isfield(H,'per') 10 | H = rmfield ( H,'per'); 11 | end 12 | if isfield(H,'nx') 13 | H = rmfield ( H,'nx'); 14 | end 15 | if isfield(H,'ny') 16 | H = rmfield ( H,'ny'); 17 | end 18 | if isfield(H,'nz') 19 | H = rmfield ( H,'nz'); 20 | end 21 | if isfield(H,'Z') 22 | H = rmfield ( H,'Z'); 23 | end 24 | if isfield(H,'XX') 25 | H = rmfield ( H,'XX'); 26 | end 27 | if isfield(H,'YY') 28 | H = rmfield ( H,'YY'); 29 | end 30 | if isfield(H,'x_orig') 31 | H = rmfield ( H,'x_orig'); 32 | end 33 | if isfield(H,'y_orig') 34 | H = rmfield ( H,'y_orig'); 35 | end 36 | if isfield(H,'lay') 37 | H = rmfield ( H,'lay'); 38 | end 39 | if isfield(H,'dat') 40 | H = rmfield ( H,'dat'); 41 | end 42 | if isfield(H,'AA') 43 | H = rmfield ( H,'AA'); 44 | end 45 | if isfield(H,'mesh_rot') 46 | H = rmfield ( H,'mesh_rot'); 47 | end 48 | if isfield(H,'res') 49 | H = rmfield ( H,'res'); 50 | end 51 | if isfield(H,'use_it') 52 | H = rmfield ( H,'use_it'); 53 | end 54 | if isfield(H,'lay_to_c') 55 | H = rmfield ( H,'lay_to_c'); 56 | end 57 | if isfield(H,'f_t') 58 | H = rmfield ( H,'f_t'); 59 | end 60 | 61 | guidata(hObject, H); 62 | end % end clear_variables_in_H -------------------------------------------------------------------------------- /M3D/M3_del_col.m: -------------------------------------------------------------------------------- 1 | function M3_del_col(hObject,eventdata,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | return 8 | end 9 | 10 | newXLim = get(H.axes1,'XLim'); 11 | newYLim = get(H.axes1,'YLim'); 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | while 1 16 | [za,~,zc]=ginput(1); 17 | if zc==3 18 | break 19 | end 20 | xbu=abs(H.YY-za); xbu=find(min(xbu)==xbu); 21 | H.YY(xbu)=[]; 22 | 23 | if isfield(H,'AAt') 24 | H.AAt(:,xbu,:)=[]; 25 | else 26 | H.AA(:,xbu,:)=[]; 27 | end 28 | 29 | H.nx=length(H.XX); H.ny=length(H.YY); 30 | 31 | M3_update_model_plot(H) 32 | set(H.axes1,'XLim',newXLim) 33 | set(H.axes1,'YLim',newYLim) 34 | end 35 | 36 | M3_update_model_plot(H) 37 | 38 | if ~isfield(H,'undo') 39 | H.undo=0; 40 | end 41 | H.undo=H.undo+1; 42 | 43 | % M3_save_undo(hObject, eventdata, H) 44 | 45 | guidata(hObject, H) 46 | 47 | end % end del_col_Callback -------------------------------------------------------------------------------- /M3D/M3_del_row.m: -------------------------------------------------------------------------------- 1 | function M3_del_row(hObject,eventdata,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | return 8 | end 9 | 10 | newXLim = get(H.axes1,'XLim'); 11 | newYLim = get(H.axes1,'YLim'); 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | while 1 16 | [~,zb,zc]=ginput(1); 17 | if zc==3 18 | break 19 | end 20 | xbu=abs(H.XX-zb); xbu=find(min(xbu)==xbu); 21 | H.XX(xbu)=[]; 22 | 23 | if isfield(H,'AAt') 24 | H.AAt(xbu,:,:)=[]; 25 | else 26 | H.AA(xbu,:,:)=[]; 27 | end 28 | 29 | H.nx=length(H.XX); H.ny=length(H.YY); 30 | 31 | M3_update_model_plot(H) 32 | set(H.axes1,'XLim',newXLim) 33 | set(H.axes1,'YLim',newYLim) 34 | end 35 | 36 | M3_update_model_plot(H) 37 | 38 | if ~isfield(H,'undo') 39 | H.undo=0; 40 | end 41 | H.undo=H.undo+1; 42 | 43 | % M3_save_undo(hObject, eventdata, H) 44 | 45 | guidata(hObject, H) 46 | 47 | 48 | end % end del_row_Callback -------------------------------------------------------------------------------- /M3D/M3_delete_layers.m: -------------------------------------------------------------------------------- 1 | function M3_delete_layers(hObject, ~, ~) 2 | H=guidata(hObject); 3 | 4 | if isfield(H,'AAt') 5 | isearth = squeeze(sum(sum(H.AAt<1e16,1),2)); % find earth cells per layer 6 | elseif isfield(H,'AA') 7 | isearth = squeeze(sum(sum(H.AA<1e16,1),2)); % find earth cells per layer 8 | else 9 | warndlg('No mesh found','Error') 10 | end 11 | 12 | figure 13 | plot(isearth,'ko'); hold on; plot(isearth,'k-') 14 | xlabel('Layer number') 15 | ylabel('Number of non-air cells') 16 | 17 | list = cellstr(cat(2,repmat('Layer ',[H.nz-1 1]),num2str((1:H.nz-1)'),repmat(': ',[H.nz-1 1]),num2str(H.Z(1:end-1)'))); % H.nz-1 since M3 counts all edges 18 | 19 | [sel,val] = listdlg('PromptString','Select layers to delete (depth in km)','ListString',list,'Name','Delete Layers','ListSize',[300 300]); 20 | 21 | if ~val 22 | disp('No layers selected. Returning to Main Menu') 23 | 24 | else % layers selected to be deleted 25 | 26 | flag = 0; 27 | for i = 1:length(sel) % check for stations in selected layers 28 | if sum(H.d.z./1000 >= H.Z(sel(i))) > 0 && sum(H.d.z./1000 <= H.Z(sel(i)+1)) > 0 % if a station is in a selected layer 29 | flag = 1; 30 | end 31 | end 32 | 33 | if flag 34 | answer = questdlg('WARNING: Some stations are located in layers to be deleted. Stations elevations will be moved. Proceed?','WARNING','Yes','No','No'); 35 | if ~strcmp(answer,'Yes') 36 | return 37 | end 38 | end 39 | 40 | uiwait(msgbox([num2str(length(sel)),' layers removed from model'],'Layers Deleted!','modal')) 41 | disp([num2str(length(sel)),' layers removed from model']) 42 | if isfield(H,'AAt') 43 | H.AAt(:,:,sel) = []; 44 | H.Zsurf = H.Zsurf - length(sel); 45 | H.Zsurf(H.Zsurf<=0) = 1; 46 | elseif isfield(H,'AA') 47 | H.AA(:,:,sel) = []; 48 | end 49 | H.Z(sel) = []; 50 | H.top = H.Z(1)*1000; % in m 51 | H.nz = H.nz-length(sel); 52 | M3_update_model_plot(H) 53 | 54 | end 55 | 56 | guidata(hObject, H); 57 | end -------------------------------------------------------------------------------- /M3D/M3_get_srtm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/M3D/M3_get_srtm.m -------------------------------------------------------------------------------- /M3D/M3_jump_to_layer.m: -------------------------------------------------------------------------------- 1 | function M3_jump_to_layer(hObject,~,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | else 8 | newXLim = get(H.axes1,'XLim'); 9 | newYLim = get(H.axes1,'YLim'); 10 | % view_model_Callback(hObject, eventdata, H) 11 | 12 | if str2double(get(H.lay_num,'String')) < 1 || str2double(get(H.lay_num,'String')) > H.nz -1 13 | warndlg('Enter a valid layer number.') 14 | % set(H.lay_num,'String','1') 15 | return 16 | else 17 | H.lay = str2double(get(H.lay_num,'String')); 18 | end 19 | 20 | M3_update_model_plot(H) 21 | set(H.axes1,'XLim',newXLim) 22 | set(H.axes1,'YLim',newYLim) 23 | if get(H.gridlines,'value') 24 | shading flat 25 | else 26 | shading faceted 27 | end 28 | end 29 | 30 | guidata(hObject, H) 31 | 32 | end -------------------------------------------------------------------------------- /M3D/M3_load_mat_legacy.m: -------------------------------------------------------------------------------- 1 | function M3_load_mat_legacy(hObject,~) 2 | % Load data from .mat file 3 | 4 | H=guidata(gcbo); 5 | 6 | [dat,~] = uigetfile({'*.mat'},'pick mat file'); 7 | if dat == 0 8 | return 9 | end 10 | 11 | M3_clear_var_in_H(hObject,H); 12 | 13 | H.mesh_rot = 0; 14 | 15 | delete undo* 16 | H.undo=0; 17 | 18 | H.lay=1; 19 | sttol=str2double(H.stat_tol); 20 | 21 | set(H.axes1,'HandleVisibility','ON'); 22 | axes(H.axes1) 23 | 24 | matfile = load(dat); 25 | H.dat = dat; 26 | 27 | d.loc = [matfile.coord(:,2) matfile.coord(:,1) -matfile.coord(:,3)]; % negated z here for depth b.s.l. 28 | d.Z = permute(matfile.ZZZ,[2 1 3]); 29 | d.Zerr = permute(matfile.EEE,[2 1 3]) + (1i .* permute(matfile.EEE,[2 1 3])); 30 | d.tip = permute(matfile.ZZZ_HZ,[2 1 3]); 31 | d.tiperr = permute(matfile.EEE_HZ,[2 1 3]) + (1i .* permute(matfile.EEE_HZ,[2 1 3])); 32 | d.site = matfile.site'; 33 | d.T = matfile.T; 34 | d.ns = length(d.Z(1,1,:)); 35 | d.nf = length(d.Z(:,1,1)); 36 | d.nr = 4; 37 | 38 | H.d = d; 39 | 40 | long = H.d.loc(:,2); 41 | lat = H.d.loc(:,1); 42 | H.cent_lat = (max(lat)+min(lat))/2; 43 | H.cent_long = (max(long)+min(long))/2; 44 | % Convert station coords from degrees to km N-S and E-W 45 | [H.d.y,H.d.x] = geo2utm(long,lat,H.cent_long,H.cent_lat); 46 | H.d.y = H.d.y - 500000; % 500 kilometers is subtracted to put the center of the mesh at 0km (UTM uses 500km as the cent_long point) 47 | 48 | H.d.z = H.d.loc(:,3); % x = NS direction, y = EW direction, z = depth b.s.l. as in ModEm inversion 49 | 50 | H.x_orig=H.d.x; H.y_orig=H.d.y; % not used much, set_rot uses this but maybe not needed 51 | plot(H.d.y./1000,H.d.x./1000,'vk','markerfacecolor','b'); axis equal; xlabel('Easting (km)'); ylabel('Northing (km)') 52 | axis([min(H.d.y./1000)-sttol max(H.d.y./1000)+sttol min(H.d.x./1000)-sttol max(H.d.x./1000)+sttol]); 53 | text(H.d.y./1000,H.d.x./1000,H.d.site,'fontsize',11,'FontWeight','bold'); 54 | 55 | guidata(hObject, H); 56 | 57 | end % end load_mat_Callback -------------------------------------------------------------------------------- /M3D/M3_load_mat_new.m: -------------------------------------------------------------------------------- 1 | function M3_load_mat_new(hObject,~) 2 | 3 | H=guidata(gcbo); 4 | 5 | [dat,~] = uigetfile({'*.mat'},'Pick .mat file'); 6 | if dat == 0 7 | return 8 | end 9 | 10 | M3_clear_var_in_H(hObject,H); 11 | 12 | H.mesh_rot = 0; 13 | 14 | delete undo* 15 | H.undo=0; 16 | 17 | H.lay=1; 18 | sttol=str2double(H.stat_tol); 19 | 20 | set(H.axes1,'HandleVisibility','ON'); 21 | axes(H.axes1) 22 | 23 | matfile = load(dat); 24 | H.d = matfile.d; 25 | H.dat = dat; 26 | 27 | long = H.d.loc(:,2); 28 | lat = H.d.loc(:,1); 29 | H.cent_lat = (max(lat)+min(lat))/2; 30 | H.cent_long = (max(long)+min(long))/2; 31 | % Convert station coords from degrees to km N-S and E-W 32 | if isfield(H.d,'x') 33 | H.d.y = matfile.d.y; 34 | H.d.x = matfile.d.x; 35 | else 36 | [H.d.y,H.d.x] = geo2utm(long,lat,H.cent_long,H.cent_lat); 37 | H.d.y= H.d.y - 500000; % 500 kilometers is subtracted to put the center of the mesh at 0km (UTM uses 500km as the cent_long point) 38 | end 39 | H.d.z = -H.d.loc(:,3); % note x = NS direction, y = EW direction, z = depth b.s.l. as in ModEM inversion 40 | 41 | H.x_orig = H.d.x; H.y_orig = H.d.y; % this might not be needed, currently used by set_rot 42 | plot(H.d.y./1000,H.d.x./1000,'vk','markerfacecolor','b'); axis equal; xlabel('Easting (km)'); ylabel('Northing (km)') 43 | axis([min(H.d.y./1000)-sttol max(H.d.y./1000)+sttol min(H.d.x./1000)-sttol max(H.d.x./1000)+sttol]); 44 | text(H.d.y./1000,H.d.x./1000,H.d.site,'fontsize',11,'FontWeight','bold'); 45 | 46 | guidata(hObject, H); 47 | 48 | end % end load_mat_new_Callback -------------------------------------------------------------------------------- /M3D/M3_load_modem_data.m: -------------------------------------------------------------------------------- 1 | function M3_load_modem_data(hObject, ~) 2 | 3 | H=guidata(gcbo); 4 | 5 | [file,~] = uigetfile({'*.data'},'Pick ModEM data file'); 6 | if file == 0 7 | return 8 | end 9 | 10 | M3_clear_var_in_H(hObject,H); 11 | 12 | H.mesh_rot = 0; 13 | 14 | delete undo* 15 | H.undo=0; 16 | 17 | H.lay=1; 18 | sttol=str2double(H.stat_tol); 19 | 20 | set(H.axes1,'HandleVisibility','ON'); 21 | axes(H.axes1) 22 | 23 | H.d = load_data_modem(file); 24 | H.dat = file; % save filename only for having a seed name for the parameter file 25 | 26 | % edit 2019 - plot x and y from data file instead. lat and lon in ModEm data file won't be 27 | % right if file generated from rotated mesh 28 | long = H.d.loc(:,2); 29 | lat = H.d.loc(:,1); 30 | H.cent_lat = (max(lat)+min(lat))/2; 31 | H.cent_long = (max(long)+min(long))/2; 32 | % % Convert station coords from degrees to km N-S and E-W 33 | [H.d.y,H.d.x] = geo2utm(long,lat,H.cent_long,H.cent_lat); 34 | H.d.y=H.d.y-500000; % 500 kilometers is subtracted to put the center of the mesh at 0km (UTM uses 500km as the cent_long point) 35 | 36 | H.d.z = -H.d.loc(:,3); % note x = NS direction, y = EW direction, z = depth b.s.l. as in ModEM inversion 37 | % H.x = H.d.y./1000; H.y = H.d.x./1000; % switch x and y for M3 plotting 38 | 39 | H.x_orig=H.d.x; H.y_orig=H.d.y; 40 | plot(H.d.y./1000,H.d.x./1000,'vk','markerfacecolor','b'); axis equal; xlabel('Easting (km)'); ylabel('Northing (km)') 41 | axis([min(H.d.y./1000)-sttol max(H.d.y./1000)+sttol min(H.d.x./1000)-sttol max(H.d.x./1000)+sttol]); 42 | text(H.d.y./1000,H.d.x./1000,H.d.site,'fontsize',11,'FontWeight','bold'); 43 | 44 | guidata(hObject, H); 45 | 46 | end % end load_modem_data_Callback -------------------------------------------------------------------------------- /M3D/M3_load_modem_mod.m: -------------------------------------------------------------------------------- 1 | function M3_load_modem_mod(hObject, ~, ~) 2 | % Load ModEM format model file 3 | 4 | H=guidata(hObject); 5 | delete undo* 6 | 7 | if ~isfield(H,'dat') 8 | warndlg('Load data file first') 9 | return 10 | end 11 | 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | [mod_mod, mod_path] = uigetfile('*.*','Select ModEM model file'); 16 | 17 | [m] = load_model_modem([mod_path mod_mod]); 18 | 19 | H.top = m.origin(3); 20 | H.nx = m.nx; 21 | H.ny = m.ny; 22 | H.nz = m.nz; 23 | H.XX = m.dx; 24 | H.YY = m.dy; 25 | H.Z = m.dz; 26 | H.AA = m.A; 27 | H.lay = 1; % just set view to first layer 28 | 29 | %now set the model variables so they match the generated model variables 30 | 31 | H.AA(H.nx+1,:,:)=H.AA(H.nx,:,:); 32 | H.AA(:,H.ny+1,:)=H.AA(:,H.ny,:); 33 | H.AA(:,:,H.nz+1)=H.AA(:,:,H.nz); 34 | 35 | H.XX = (m.x./1000)'; 36 | H.YY = m.y./1000; 37 | H.Z = (m.z./1000)'; 38 | 39 | H.nx=H.nx+1; 40 | H.ny=H.ny+1; 41 | H.nz=H.nz+1; 42 | 43 | H.m = m; 44 | 45 | M3_update_model_plot(H) 46 | 47 | guidata(hObject, H); 48 | 49 | end % end load_modem_mod_Callback -------------------------------------------------------------------------------- /M3D/M3_load_param.m: -------------------------------------------------------------------------------- 1 | function load_M3_param_Callback(hObject,~,~) % works with new par file format 2 | 3 | H=guidata(hObject); 4 | 5 | pause(0.1) 6 | [parname,path]=uigetfile('par_*.m','Read in parameter file'); 7 | par = load([path,parname]); 8 | 9 | set(H.xspacing,'string',num2str(par(1))); 10 | set(H.yspacing,'string',num2str(par(2))); % spacing in y (m) 11 | set(H.moutcX,'string',num2str(par(3))); % mesh out the core in X 12 | set(H.Xinc,'string',num2str(par(4))); % increase in X by 13 | set(H.moutcY,'string',num2str(par(5))); % mesh out the core in Y 14 | set(H.Yinc,'string',num2str(par(6))); % increase in Y by 15 | set(H.firstthick,'string',num2str(par(7))); % First Thickness 16 | set(H.nl,'string',num2str(par(8))); % number of layers 17 | set(H.Zinc,'string',num2str(par(9))); % increase thickness by 18 | set(H.airspacing,'string',num2str(par(10))); % air cell thickness 19 | set(H.res,'string',num2str(par(11))); % halfspace resistivity 20 | set(H.min_per,'string',num2str(par(12))); % minimum period to use 21 | set(H.max_per,'string',num2str(par(13))); % maximum period to use 22 | set(H.per_skip,'string',num2str(par(14))); % periods to skip 23 | set(H.errflr_Zdiag,'string',num2str(par(15))); % xx and yy error floor (%) 24 | set(H.errflr_Zodiag,'string',num2str(par(16))); % xy and yx error floor (%) 25 | set(H.errflr_tip,'string',num2str(par(17))); %tipper error floor (absolute) 26 | set(H.errflr_type,'string',num2str(par(18))); 27 | set(H.resp,'value',par(19)); % 1=FT only, 2=FT+tip, 3=off diag Z only, 4=tip only 28 | set(H.conj_Z,'value',par(20)); % 0 = don't conjugate Z, 1= conjugate Z 29 | set(H.conj_tip,'value',par(21)); % 0 = don't conjugate tipper, 1= conjugate tipper 30 | 31 | disp(['File ',parname,' successfully loaded.']) 32 | 33 | guidata(hObject, H); 34 | 35 | end % end load_M3_param_Callback -------------------------------------------------------------------------------- /M3D/M3_load_ws_mod.m: -------------------------------------------------------------------------------- 1 | function M3_load_ws_mod(hObject, ~, ~) 2 | % Load wsinv3dmt format model file 3 | 4 | H=guidata(hObject); 5 | delete undo* 6 | 7 | if ~isfield(H,'dat') 8 | warndlg('Load data file first') 9 | return 10 | end 11 | 12 | set(H.axes1,'HandleVisibility','ON'); 13 | axes(H.axes1); 14 | 15 | [name,~] = uigetfile({'*'},'pick wsinv3dmt file'); 16 | 17 | [m] = load_model_wsinv(name); 18 | 19 | H.top = m.origin(3); 20 | H.nx = m.nx; 21 | H.ny = m.ny; 22 | H.nz = m.nz; 23 | H.XX = m.dx; 24 | H.YY = m.dy; 25 | H.Z = m.dz; 26 | H.AA = round(m.A); 27 | H.lay = 1; % just set view to first layer 28 | 29 | %now set the model variables so they match the generated model variables 30 | % H.AA, H.nx, H.ny, H.nz include ALL model edges and thus have 1 more 31 | % entry than their m structure counterparts 32 | 33 | H.AA(H.nx+1,:,:)=H.AA(H.nx,:,:); 34 | H.AA(:,H.ny+1,:)=H.AA(:,H.ny,:); 35 | H.AA(:,:,H.nz+1)=H.AA(:,:,H.nz); 36 | 37 | H.XX = (m.x./1000)'; 38 | H.YY = m.y./1000; 39 | H.Z = (m.z./1000)'; 40 | 41 | H.nx=H.nx+1; 42 | H.ny=H.ny+1; 43 | H.nz=H.nz+1; 44 | 45 | H.m = m; 46 | 47 | M3_update_model_plot(H) 48 | 49 | guidata(hObject, H); 50 | 51 | end % end load_ws_mod_Callback -------------------------------------------------------------------------------- /M3D/M3_make_modem_cov.m: -------------------------------------------------------------------------------- 1 | function M3_make_modem_cov(hObject, ~, ~) 2 | % Write a ModEM .cov file for inversion, editable values 3 | 4 | H=guidata(hObject); 5 | 6 | if isfield(H,'m') % must have model resistivities before making cov file 7 | 8 | prompt = {sprintf('Enter .cov file settings\n\nFile name'),'x smoothing (Default: 0.3)','y smoothing (Default: 0.3)','z smoothing (Default: 0.3)',sprintf('number of times smoothing applied\n(Default: 1)')}; 9 | dlg_title = 'Cov File'; 10 | def = {'modem.cov','0.3','0.3','0.3','1'}; 11 | answer = inputdlg(prompt,dlg_title,1,def); 12 | 13 | indm = ones(H.nx-1,H.ny-1,H.nz-1); 14 | 15 | if isfield(H,'AAt') % if topo was added in current M3 session 16 | A = H.AAt(1:H.nx-1,1:H.ny-1,1:H.nz-1); 17 | else 18 | A = H.AA(1:H.nx-1,1:H.ny-1,1:H.nz-1); 19 | end 20 | 21 | if get(H.fix_ocean,'Value') %If "fix ocean" box is checked 22 | indm(A==str2double(get(H.ocean_res,'string'))) = 9; % fix ocean cell values with 9. 23 | end 24 | 25 | indm(A==10^17) = 0; % cov file sets air cells to zero smoothing 26 | indm(isnan(A)) = 0; % if imported model, air cells are NaN 27 | 28 | nzz=H.nz-1; 29 | cfile=answer{1}; 30 | cov = indm; % rot90(fliplr(indm)); % previously the xy swap was done here 31 | xsmooth = str2double(answer{2})*ones(nzz,1); % these need to be vectors 32 | ysmooth = str2double(answer{3})*ones(nzz,1); 33 | zsmooth = str2double(answer{4}); 34 | nsmooth = str2double(answer{5}); 35 | % note cov file format is different than model file... values for 36 | % each layer are printed as nx x ny 37 | [status] = write_modem_covariance(cfile,cov,xsmooth,ysmooth,zsmooth,nsmooth); 38 | else 39 | warndlg('No matrix of resistivity indices found- save ModEM model file first!','Error') 40 | end 41 | 42 | guidata(hObject, H); 43 | 44 | end % end make_modem_cov_Callback -------------------------------------------------------------------------------- /M3D/M3_make_param.m: -------------------------------------------------------------------------------- 1 | function make_M3_param_Callback(hObject, ~, ~) % format has changed to allow loading 2 | H=guidata(hObject); 3 | 4 | if isfield(H,'dat') 5 | filename=['par_',strtok(H.dat,'.'),'.m']; 6 | else 7 | warndlg('Need to load data before saving a parameter file.') 8 | return 9 | end 10 | 11 | if exist(filename,'file')==2 12 | filename=uiputfile('par_*.m','Parameter file already exists!',filename); 13 | end 14 | 15 | fid=fopen(filename,'w'); 16 | 17 | fprintf(fid,'%s\n',[get(H.xspacing,'string'),' % spacing in x (m)']); 18 | fprintf(fid,'%s\n',[get(H.yspacing,'string'),' % spacing in y (m)']); 19 | fprintf(fid,'%s\n',[get(H.moutcX,'string'),' % mesh out the core in X']); 20 | fprintf(fid,'%s\n',[get(H.Xinc,'string'),' % increase in X by']); 21 | fprintf(fid,'%s\n',[get(H.moutcY,'string'),' % mesh out the core in Y']); 22 | fprintf(fid,'%s\n',[get(H.Yinc,'string'),' % increase in Y by']); 23 | fprintf(fid,'%s\n',[get(H.firstthick,'string'),' % First Thickness']); 24 | fprintf(fid,'%s\n',[get(H.nl,'string'),' % number of layers']); 25 | fprintf(fid,'%s\n',[get(H.Zinc,'string'),' % increase thickness by']); 26 | fprintf(fid,'%s\n',[get(H.airspacing,'string'),' % air cell thickness']); 27 | fprintf(fid,'%s\n',[get(H.res,'string'),' % halfspace resistivity']); 28 | 29 | fprintf(fid,'%s\n',[get(H.min_per,'string'),' % minimum period to use']); 30 | fprintf(fid,'%s\n',[get(H.max_per,'string'),' % maximum period to use']); 31 | fprintf(fid,'%s\n',[get(H.per_skip,'string'),' % export every nth period']); 32 | fprintf(fid,'%s\n',[get(H.errflr_Zdiag,'string'),' % xx and yy error floor (%)']); 33 | fprintf(fid,'%s\n',[get(H.errflr_Zodiag,'string'),' % xy and yx error floor (%)']); 34 | fprintf(fid,'%s\n',[get(H.errflr_tip,'string'),' %tipper error floor (absolute)']); 35 | fprintf(fid,'%s\n',[get(H.errflr_type,'string'),' %error floor type']); 36 | fprintf(fid,'%s\n',[num2str(get(H.resp,'value')),' % [1= full tensor] [2= full tensor and tip] [3= off-diag only] [4= tip only]']); 37 | fprintf(fid,'%s\n',[num2str(get(H.conj_Z,'value')),' % 0= no conj Z, 1=conj Z']); 38 | fprintf(fid,'%s\n',[num2str(get(H.conj_tip,'value')),' % 0= no conj tip, 1=conj tip']); 39 | 40 | fclose(fid); 41 | 42 | disp([filename,' created']) 43 | 44 | guidata(hObject, H); 45 | 46 | end -------------------------------------------------------------------------------- /M3D/M3_make_ws_startup.m: -------------------------------------------------------------------------------- 1 | function M3_make_ws_startup(hObject, ~, ~) 2 | % Writes startup file for wsinv3dmt. 3 | 4 | H=guidata(hObject); 5 | 6 | [data_file,~] = uigetfile({'*'},' choose data file'); 7 | [model_file,~] = uigetfile({'*'},' choose initial model file'); 8 | 9 | s_prompt = {'data file:','initial model file:','output file:','priori model file(leave empty for default):','control model index(leave empty for default):','Target R.M.S.:','Max number of iterations:'... 10 | ,'Model length scale(leave empty for default):','Lagrange info(leave empty for default):','Error tol. level(leave empty for default):', 'Number of responses (12, 8, or 4)','Z error floor','Tipper error floor'}; 11 | s_titles = 'Choose startup parameters'; 12 | out_file=['out_',model_file];def='default'; 13 | s_def= {data_file,model_file,out_file,'','','1.','10','','','','12','5','15'}; %Turkiye 14 | def_lim = char(inputdlg(s_prompt,s_titles,1,s_def)); 15 | for spa=4:10 16 | if def_lim(spa,1:2)==' ' 17 | def_lim(spa,1:7)='default'; 18 | end 19 | end 20 | nr=str2double(def_lim(11,:)); 21 | if nr == 12 22 | inv_type='5'; 23 | elseif nr== 8 24 | inv_type='1'; 25 | elseif nr == 4 26 | inv_type='2'; 27 | end %there are also only tipper; and Zxy, Zyx, tipper inversions possible as well (define yourself!) 28 | line{1}=['INVERSION_TYPE ',inv_type]; 29 | line{2}=['DATA_FILE ',def_lim(1,:)]; 30 | line{3}=['MIN_ERROR_Z ',def_lim(12,:)]; 31 | line{4}=['MIN_ERROR_T ',def_lim(13,:)]; 32 | line{5}=['OUTPUT_FILE ',def_lim(3,:)]; 33 | line{6}=['INITIAL_MODEL_FILE ',def_lim(2,:)]; 34 | line{7}=['PRIOR_MODEL_FILE ',def_lim(4,:)]; 35 | line{8}=['CONTROL_MODEL_INDEX ',def_lim(5,:)]; 36 | line{9}=['TARGET_RMS ',def_lim(6,:)]; 37 | line{10}=['MAX_NO_ITERATION ',def_lim(7,:)]; 38 | line{11}=['MODEL_LENGTH_SCALE ',def_lim(8,:)]; 39 | line{12}=['LAGRANGE_INFO ',def_lim(9,:)]; 40 | line{13}=['ERROR_TOL_LEVEL ',def_lim(10,:)]; 41 | fid=fopen('startup','w'); 42 | if nr ==12 43 | for poi=1:13 44 | fprintf(fid,'%s\n',line{poi}); 45 | end 46 | else %no tipper error is output 47 | for poi=1:3 48 | fprintf(fid,'%s\n',line{poi}); 49 | end 50 | for poi=4:13 51 | fprintf(fid,'%s\n',line{poi}); 52 | end 53 | end 54 | 55 | fclose(fid); 56 | guidata(hObject, H); 57 | 58 | end -------------------------------------------------------------------------------- /M3D/M3_max_res.m: -------------------------------------------------------------------------------- 1 | function M3_max_res(hObject,~) 2 | H=guidata(gcbo); 3 | set(H.max_res,'String',get(hObject,'String')) 4 | if isfield(H,'XX') 5 | M3_update_model_plot(H) 6 | end 7 | guidata(hObject, H); 8 | end -------------------------------------------------------------------------------- /M3D/M3_min_res.m: -------------------------------------------------------------------------------- 1 | function M3_min_res(hObject,~) 2 | H=guidata(gcbo); 3 | set(H.min_res,'String',get(hObject,'String')) 4 | if isfield(H,'XX') 5 | M3_update_model_plot(H) 6 | end 7 | guidata(hObject, H); 8 | end -------------------------------------------------------------------------------- /M3D/M3_next_layer.m: -------------------------------------------------------------------------------- 1 | function M3_next_layer(hObject,~,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then modify it using these butttons.') 7 | else 8 | newXLim = get(H.axes1,'XLim'); 9 | newYLim = get(H.axes1,'YLim'); 10 | % view_model_Callback(hObject, eventdata, H) 11 | 12 | if H.lay1 14 | H.lay=H.lay-1; 15 | else 16 | warndlg('Invalid layer number.') 17 | H.lay=1; 18 | end 19 | M3_update_model_plot(H) 20 | set(H.axes1,'XLim',newXLim) 21 | set(H.axes1,'YLim',newYLim) 22 | if get(H.gridlines,'value') 23 | shading flat 24 | else 25 | shading faceted 26 | end 27 | end 28 | 29 | guidata(hObject, H) 30 | 31 | end -------------------------------------------------------------------------------- /M3D/M3_smooth_air.m: -------------------------------------------------------------------------------- 1 | function M3_smooth_air(hObject, ~, ~) 2 | H=guidata(hObject); 3 | 4 | if isfield(H,'AAt') % topography was added in current M3 session 5 | isair = squeeze(sum(sum(H.AAt>1e16,1),2)); % find number of NaN cells per layer 6 | model = H.AAt; 7 | elseif sum(sum(isnan(H.AA(:,:,1)))) > 0 % model might be loaded with topography 8 | isair = squeeze(sum(sum(isnan(H.AA),1),2)); % find number of NaN air cells per layer 9 | model = H.AA; 10 | else 11 | warndlg('No mesh with topography found','Error') 12 | return 13 | end 14 | 15 | figure 16 | plot(isair,'ko'); hold on; plot(isair,'k-') 17 | xlabel('Layer number') 18 | ylabel('Number of air cells') 19 | 20 | smth = questdlg('Smooth the last air layer? This will remove all air cells from the last layer, placing it entirely underground','Smooth last air layer?','Yes','No','No'); 21 | switch smth 22 | case 'Yes' 23 | ind = find(isair>0,1,'last'); % this ensures it is the lowest elevation air layer 24 | % [~,ind] = min(isair(isair>0)); 25 | res = str2double(get(H.res,'string')); 26 | lay = model(:,:,ind); 27 | lay(lay>1e16) = res; 28 | lay(isnan(lay)) = res; 29 | model(:,:,ind) = lay; 30 | disp(['Layer ',num2str(ind),' air cells replaced with ',num2str(res),' Ohm-m cells']) 31 | uiwait(msgbox(['Layer ',num2str(ind),' air cells replaced with ',num2str(res),' Ohm-m cells'],'Last Air Layer Smoothed','modal')) 32 | H.lay = ind; 33 | case 'No' 34 | disp('Last air layer not smoothed') 35 | return 36 | end 37 | 38 | % update the model 39 | if isfield(H,'AAt') % topography was added in current M3 session 40 | H.AAt = model; 41 | elseif sum(sum(isnan(H.AA(:,:,1)))) < H.nx*H.ny % model might be loaded with topography 42 | H.AA = model; 43 | end 44 | 45 | M3_update_model_plot(H) 46 | 47 | guidata(hObject, H); 48 | end -------------------------------------------------------------------------------- /M3D/M3_update_model_plot.m: -------------------------------------------------------------------------------- 1 | function M3_update_model_plot(H) 2 | % Dec 2019 - x and y directions made consistent with ModEM 3 | min_res = log10(str2double(get(H.min_res,'string'))); % Get the min resistivity 4 | max_res = log10(str2double(get(H.max_res,'string'))); % Get the max resistivity 5 | colim=[min_res-0.15 max_res+0.15]; % caxis values for color plots 6 | %0.15 to make figures same as pmv* because WS did so... 7 | cmap=jet(24); 8 | cmap([23 21 19 17 15 13 11 9 7 5 3],:)=[]; 9 | cmap=flipud(cmap); 10 | 11 | set(H.axes1,'HandleVisibility','ON'); 12 | axes(H.axes1); 13 | if isfield(H,'AAt') 14 | aa=reshape(H.AAt(:,:,H.lay),H.nx,H.ny); 15 | else 16 | aa=reshape(H.AA(:,:,H.lay),H.nx,H.ny); 17 | end 18 | aa(aa==1e17)=NaN; % make air cells plot as white with pcolor 19 | pcolor(H.axes1,H.YY,H.XX,log10(aa)); hold on; 20 | plot(H.d.y./1000,H.d.x./1000,'vk','markerfacecolor','b'); hold off 21 | axis equal; axis tight 22 | title(['Layer = ',num2str(H.lay),', Depth = ',num2str(H.Z(H.lay)),' to ',num2str(H.Z(H.lay+1)),' km']); 23 | xlabel('Y (km)'); ylabel('X (km)') 24 | caxis(colim); colormap(cmap); 25 | hcb=colorbar('ver','position',[0.7 0.1 0.02309 0.1977]); 26 | set(hcb,'YTick',[-1,-.5,0 0.5,1,1.5,2,2.5,3,3.5,4],... 27 | 'YTickLabel',{'0.1','0.3','1','3','10','30','100','300','1000','3000','10000'}); 28 | ylabel(hcb,'Resistivity (\Omegam)','fontsize',12); 29 | set(hcb,'yaxislocation','left'); 30 | 31 | newstring = sprintf('%s\n%s\n%s\n%s\n%s','Mesh info',['Maximum depth=',num2str(H.Z(end),'%.2f'),' km'],... 32 | ['E-W Dist from center =',num2str(abs(min(H.YY)),'%.2f'),' km'],... 33 | ['N-S Dist from center =',num2str(abs(min(H.XX)),'%.2f'),' km'],... 34 | ['NX=',num2str(H.nx-1),', NY=',num2str(H.ny-1),', NZ=',num2str(H.nz-1)]); 35 | set(H.model_text,'string',newstring) 36 | 37 | end -------------------------------------------------------------------------------- /M3D/M3_view_model.m: -------------------------------------------------------------------------------- 1 | function M3_view_model(hObject,~,~) 2 | 3 | H=guidata(hObject); 4 | 5 | if ~isfield(H,'m') 6 | warndlg('Generate a model then view it.') 7 | else 8 | M3_update_model_plot(H) 9 | end 10 | 11 | end % end view_model_Callback -------------------------------------------------------------------------------- /MT_Analysis/Bostick/bostick1.m: -------------------------------------------------------------------------------- 1 | function [rho_bostick_av,d_av, rho_berd_av,pha_berd_av] = bostick1(Z1,T) 2 | 3 | % Basic Bostick transform to covert apparent resistivity and 4 | % phase, to resistivity as a function of depth 5 | % The method using here is the simplized approximate way which uses the 6 | % phase in the equation 7 | 8 | % Written by Enci Wang, 2014 9 | % Editted by MJU April 2014 10 | 11 | nfreq = length(T); 12 | mu = 4*pi*1e-7;rad = 180./pi; 13 | % Loop over MT frequencies 14 | for ifreq = 1:nfreq 15 | w(ifreq) = 2.*pi/T(ifreq); 16 | end 17 | 18 | % Calculate the rho_bostick using the Berdichevsky average %%%%%%%%%%% 19 | 20 | for ifreq=1:nfreq 21 | Z_berd_av(ifreq) = (Z1(1,2,ifreq)- Z1(2,1,ifreq))/2; 22 | rho_berd_av(ifreq)= abs(Z_berd_av(ifreq)*Z_berd_av(ifreq))/(w(ifreq)*mu); 23 | pha_berd_av(ifreq)= 90-rad*atan2(real(Z_berd_av(ifreq)),imag(Z_berd_av(ifreq))); 24 | pha_berd_av_rad(ifreq) = pha_berd_av(ifreq)/rad; % phase in radians 25 | if (pha_berd_av_rad(ifreq)>0) && (pha_berd_av_rad(ifreq)0) && (pha_berd_av_rad(ifreq)= pdiff_max %If the phase split for the irot rotation is larger than pdiff_max, then replace 38 | pdiff_max = dpha(irot,ifreq); 39 | ang_max(ifreq) = rot(irot); 40 | end 41 | 42 | if dpha(irot,ifreq) <= pdiff_min %If the phase split for irot rotation is smaller the pdfif_min, then replace 43 | pdiff_min = dpha(irot,ifreq); 44 | ang_min(ifreq) = rot(irot); 45 | end 46 | end 47 | end 48 | 49 | strike_max_split = ang_max; -------------------------------------------------------------------------------- /MT_Analysis/calc_polar.m: -------------------------------------------------------------------------------- 1 | function [polar] = calc_polar(d) 2 | % 3 | % Function which calculates the polar diagram (i.e, peanut) for MT data and 4 | % puts the necessary x and y coordinates for plotting into a structure 5 | % called "polar" 6 | % 7 | % Usage: [polar] = calc_polar(d) 8 | % 9 | % Inputs: "d" is standard MT data structure 10 | % Outputs: "polar" contains the x and y coordinates for the peanut diagrams 11 | % for all frequencies, stations, and impedance tensor components in the 12 | % input data 13 | % 14 | 15 | rad = 180./pi; 16 | nrot = 72; 17 | 18 | %Loop through all angles and for each angle compute x and y 19 | for irot =1:nrot+1 20 | rot_ang = (irot-1)*360./nrot; 21 | 22 | % rotate impedances 23 | [dr]=rotate_d(d,rot_ang); 24 | c = cos(rot_ang/rad); s = sin(rot_ang/rad); 25 | 26 | polar.x(:,:,:,irot) = c*abs(dr.Z); 27 | polar.y(:,:,:,irot) = s*abs(dr.Z); 28 | 29 | end 30 | -------------------------------------------------------------------------------- /MT_Analysis/calc_rho_pha.m: -------------------------------------------------------------------------------- 1 | function [rho, pha, rhoerr, phaerr] = calc_rho_pha(Z,Zerr,T) 2 | %Function which calculates apparent resistivity and phase from an impedance 3 | %which is in SI units with e^{+iwt} convention. 4 | % 5 | % Usage: [rho, pha, rhoerr, phaerr] = calc_rho_pha(Z,Zerr,T) 6 | % 7 | % 8 | % Inputs: Z and Zerr are nf x nr x ns impedances and impedance errors 9 | % T is a vector of nf x 1 periods 10 | % 11 | % Outputs: rho and pha are nf x nr x ns apparent resistivity and phases 12 | % rhoerr and phaerr are their respective nf x nr x ns errors. 13 | 14 | mu = 4*pi*10^-7; 15 | w = 2*pi./T; 16 | 17 | sze = size(Z); 18 | 19 | dZ = zeros(sze); 20 | rhoerr = zeros(sze); rho = zeros(sze); 21 | phaerr = zeros(sze); pha = zeros(sze); 22 | for i = 1:sze(1) 23 | 24 | %The formula which converts impedance to apparent resistivity and phase 25 | rho(i,:,:) = (1/(w(i)*mu))*abs(Z(i,:,:)).^2; 26 | pha(i,:,:) = atan2(imag(Z(i,:,:)),real(Z(i,:,:)))*(180/pi); 27 | 28 | %The formulas which convert impedance error to error in apparent 29 | %resistivity and phase. Greg and Juliane wrote a PDF document with the 30 | %derivation. 31 | %Use real(Zerr) 32 | dZ(i,:,:) = real(Zerr(i,:,:))./abs(Z(i,:,:)); 33 | 34 | rhoerr(i,:,:) = 2*rho(i,:,:).*(dZ(i,:,:)); 35 | %rhoerr(i,:,:) = rho(i,:,:).*((2*dZ(i,:,:))+(dZ(i,:,:)).^2); 36 | phaerr(i,:,:) = (180/pi)*dZ(i,:,:); %Phase error in degrees 37 | 38 | end 39 | 40 | -------------------------------------------------------------------------------- /MT_Analysis/calc_ssq.m: -------------------------------------------------------------------------------- 1 | function [ssqZ, ssqZerr] = calc_ssq(Z,Zerr) 2 | %Function to compute the ssq impedance of a given impedance tensor 3 | % 4 | % Usage: [ssqZ,ssqZerr] = calc_ssq(Z,Zerr) 5 | % 6 | % Inputs: Z is a nf x 4 x ns complex vector with each column being [xx,xy,yx,yy] 7 | % Zerr is an nf x 4 x ns complex vector of the same size as Z 8 | % 9 | % Outputs: ssqZ is a nf x 1 x ns complex vector of the determinant of Z 10 | % ssqZerr is an nf x 1 x ns complex vector of the errors. 11 | % Note: the error propagation is likely incorrect and should 12 | % be corrected in the future 13 | % 14 | % See Rung-Arunwan et al. (2016), On the Berdichevsky average 15 | % Rung-Arunwan et al. (2017), Use of ssq rotational invariants 16 | 17 | sze = size(Z); 18 | 19 | if length(sze)<2 20 | sze(2) = 1; 21 | end 22 | 23 | if length(sze)<3 24 | sze(3) = 1; 25 | end 26 | 27 | ssqZ = zeros(sze(1),1,sze(3)); 28 | ssqZerr = zeros(size(ssqZ)); 29 | 30 | for i = 1:sze(3) %Loop over stations 31 | 32 | %Determinant = ad - bc 33 | a = Z(:,1,i); b = Z(:,2,i); c = Z(:,3,i); d = Z(:,4,i); 34 | da = Zerr(:,1,i); db = Zerr(:,2,i); dc = Zerr(:,3,i); dd = Zerr(:,4,i); 35 | 36 | ssqZ(:,1,i) = sqrt(0.5*(a.^2+b.^2+c.^2+d.^2)); 37 | 38 | %Not sure how to handle the determinant errors. 39 | %One option is to simply take the average of the relative errors of 40 | %all the tensor components. However, this often results in 41 | %disproportionately large errors from the diagonal components 42 | %ssqZerr(:,1,i) = 0.25*abs(ssqZ).*(da./abs(a)+db./abs(b)+dc./abs(c)+dd./abs(d)); 43 | 44 | %A third option is to take the average of the off-diagonal components 45 | %only 46 | ssqZerr(:,1,i) = 0.5*abs(ssqZ).*(db./abs(b)+dc./abs(c)); 47 | 48 | end -------------------------------------------------------------------------------- /MT_Analysis/cut_beta.m: -------------------------------------------------------------------------------- 1 | function [de] = cut_beta(d,betacutoff) 2 | % 3 | % Function which removes data above a given threshold of phase tensor beta 4 | % skew 5 | % 6 | % Usage: 7 | % [de] = cut_beta(d,betacutoff) 8 | % 9 | % Inputs: 10 | % d = standard MT data structure 11 | % 12 | % Outputs: 13 | % de = standard MT data structure with edited points 14 | % 15 | % 16 | 17 | count = 1; 18 | for is = 1:d.ns % Loop over stations 19 | 20 | [p] = calc_phase_tensor(d.Z(:,:,is)); %Calculate phase tensor parameters 21 | 22 | for ip = 1:d.nf 23 | if abs(p.beta(ip))>betacutoff 24 | K(count) = is; 25 | I(count) = ip; 26 | count = count+1; 27 | 28 | end 29 | end 30 | 31 | 32 | end 33 | 34 | 35 | for i = 1:length(K) 36 | d.rho(I(i),:,K(i)) = NaN; 37 | d.pha(I(i),:,K(i)) = NaN; 38 | d.Z(I(i),:,K(i)) = NaN+1i*NaN; 39 | d.rhoerr(I(i),:,K(i)) = NaN; 40 | d.phaerr(I(i),:,K(i)) = NaN; 41 | d.Zerr(I(i),:,K(i)) = NaN+1i*NaN; 42 | end 43 | 44 | de = d; -------------------------------------------------------------------------------- /MT_Analysis/rotate_Z.m: -------------------------------------------------------------------------------- 1 | function Z_rot = rotate_Z(Z,rot) 2 | % 3 | % Function which rotates the 2 x 2 impedance tensor for a particular 4 | % frequency and location 5 | % 6 | % Usage: Z_rot = rotate_Z(Z,rot) 7 | % 8 | % Inputs: "Z" is a 1 x 4 vector of complex impedance: [Zxx Zxy Zyx Zyy] 9 | % "rot" is an angle (in degrees) to rotate the data clockwise 10 | % (negative angles is counter-clockwise) 11 | % 12 | % Outputs: "Z_rot" is the rotated 1 x 4 vector of complex impedance [Zxx Zxy Zyx Zyy] 13 | 14 | c = cosd(rot); s = sind(rot); 15 | 16 | R = [ c, -s ; s, c]; %Rotation matrix 17 | 18 | Z_rot = R'*[Z(1) Z(2); Z(3) Z(4)]*R; 19 | 20 | Z_rot = [Z_rot(1,1) Z_rot(1,2) Z_rot(2,1) Z_rot(2,2)]; -------------------------------------------------------------------------------- /MT_Analysis/rotate_d.m: -------------------------------------------------------------------------------- 1 | function [d]=rotate_d(d,rot) 2 | % 3 | % This function takes a standard data structure and rotates ALL data 4 | % (impedance and tipper) by a single rotation angle. Positive rotation 5 | % angle is clockwise and negative rotation angle is anti-clockwise. 6 | % 7 | % Usage: [d] = rotate_d(d,rot) 8 | % 9 | % Inputs: 10 | % 11 | % "d" is standard MT data structure 12 | % "rot" is the angle to rotate clockwise in degrees 13 | % 14 | % Note: The "d" data structure has impedances and tipper data which have 15 | % already been rotated by d.zrot and d.trot. So for example, if d contains 16 | % some impedance d.Z and d.zrot is 19 degrees, then d.Z has been rotated to 17 | % 19 degrees. If you then do [d_new] = rotate_d(d,10), the data will be 18 | % rotated by 10 degrees clockwise meaning that d_new will have impedances 19 | % which have been rotated to 29 degrees. This code also updates the d_new.zrot 20 | % and d_new.trot variables as well. 21 | 22 | for is = 1:d.ns 23 | 24 | for ifreq = 1:d.nf 25 | 26 | d.Z(ifreq,:,is) = rotate_Z(d.Z(ifreq,:,is),rot); 27 | d.tip(ifreq,:,is) = rotate_tip(d.tip(ifreq,:,is),rot); 28 | 29 | end 30 | 31 | end 32 | 33 | [d.rho, d.pha, d.rhoerr, d.phaerr] = calc_rho_pha(d.Z,d.Zerr,d.T); 34 | 35 | d.zrot = d.zrot + rot; % d.zrot should be nf x ns 36 | d.trot = d.trot + rot; 37 | 38 | % Leave errors unchanged. Fix later. 39 | %dz = (U.^2*dz.^2).^.5; 40 | %dz = abs(U*dz); 41 | end 42 | 43 | -------------------------------------------------------------------------------- /MT_Analysis/rotate_tip.m: -------------------------------------------------------------------------------- 1 | function tip_rot = rotate_tip(tip,rot) 2 | % 3 | % Function which rotates the tipper transfer function for a particular 4 | % tipper value 5 | % 6 | % Usage: tip_rot = rotate_tip(tip,rot) 7 | % 8 | % Inputs: "tip" is a 1 x 2 vector of complex [Tzx Tzy] 9 | % "rot" is an angle (in degrees) to rotate the data clockwise 10 | % (negative angles is counter-clockwise) 11 | % 12 | % Outputs: "tip_rot" is the rotated 1 x 2 vector of complex [Tzx Tzy] 13 | 14 | c = cosd(rot); s = sind(rot); 15 | 16 | R = [ c, -s ; s, c]; %Rotation matrix 17 | 18 | tip_rot = (R*tip.').'; -------------------------------------------------------------------------------- /MT_Analysis/shear_twist_anis.m: -------------------------------------------------------------------------------- 1 | function Z_dist=shear_twist_anis(Z, shear,twist,anis) 2 | % 3 | %Z_prime=shear_twist(Z,shear,twist) 4 | % 5 | % shear_twist(Z,shear,twist) distorts an impedance 6 | % tensor Z by applying shear and twist according 7 | % to Groom & Bailey (1989) to the tensor. 8 | % The impedance tensor has to be a 2x2xN array 9 | % while shear and twist need to be in degrees. 10 | Zmat = zeros(2,2,size(Z,1)); 11 | for i = 1:size(Z,1) 12 | Zmat(:,:,i) = [Z(i,1) Z(i,2); Z(i,3) Z(i,4)]; 13 | end 14 | 15 | % Calculating e and t 16 | e = tand(shear); 17 | t = tand(twist); 18 | 19 | % Calculating S and T 20 | S = 1/sqrt(1+e^2)*([1 e; e 1]); 21 | T = 1/sqrt(1+t^2)*([1 -t; t 1]); 22 | A = 1/sqrt(1+anis^2)*([1+anis 0; 0 1-anis]); 23 | 24 | % Calculating distorted Z 25 | Z_prime = zeros(2,2,size(Zmat,3)); 26 | for j = 1:size(Zmat,3) 27 | Z_prime(:,:,j) = T*S*A*Zmat(:,:,j); 28 | end 29 | 30 | Z_dist(:,1) = squeeze(Z_prime(1,1,:)); 31 | Z_dist(:,2) = squeeze(Z_prime(1,2,:)); 32 | Z_dist(:,3) = squeeze(Z_prime(2,1,:)); 33 | Z_dist(:,4) = squeeze(Z_prime(2,2,:)); -------------------------------------------------------------------------------- /Model_Plotting/plot_cross_section.m: -------------------------------------------------------------------------------- 1 | function [x,z,rho] = plot_cross_section(x,z,rho) 2 | %Function to plot a cross section of resistivity in log scale 3 | % 4 | % Usage: plot_cross_section(x,z,rho) 5 | % 6 | % x is the x vector to plot (km) 7 | % z is the depth vector to plot (km) 8 | % rho is the nx by nz resistivity matrix (Ohm m) 9 | 10 | u = user_defaults; 11 | 12 | %Create meshgrid of x and z values and plot as logarithmic resistivity 13 | pcolor(x,z,rho); hold on; axis ij 14 | 15 | xlabel('Distance Along Profile (km)') 16 | ylabel('Depth Below Sealevel (km)') 17 | colormap(u.cmap); caxis(u.colim); 18 | add_rho_colorbar(u); 19 | 20 | set(gca,'DataAspectRatio',[u.ve 1 1]); 21 | set(gca,'Layer','top') 22 | set(gca,'Box','on'); 23 | %set(gca,'YScale','log') 24 | 25 | if u.plot_contours 26 | contour(x,z,rho,u.contours,'-k','ShowText',u.contour_text); 27 | end -------------------------------------------------------------------------------- /Model_Plotting/plot_cross_section_2d.m: -------------------------------------------------------------------------------- 1 | function [x,y,z,rho] = plot_cross_section_2d(m,d) 2 | 3 | u = user_defaults; 4 | %close all 5 | 6 | if exist('d','var') & d.loc ~= 0 7 | figure(1); 8 | plot_site_map(d); 9 | print_figure(['vertical_profiles'],['Profile_Model_',d.niter,'_MAP']); 10 | end 11 | 12 | yind = m.npad(2)+1:m.ny-m.npad(2); 13 | zind = 1:nearestpoint(u.zmax*1000,m.cz); 14 | 15 | figure(3); hold on 16 | xlabel('Distance Along Profile (km)') 17 | ylabel('Depth Below Sealevel (km)') 18 | colormap(u.cmap); caxis(u.colim); 19 | add_rho_colorbar(u); 20 | 21 | set(gca,'DataAspectRatio',[u.ve 1 1]); 22 | 23 | [Y, Z] = meshgrid(m.cy(yind)/1000,m.cz(zind)/1000); 24 | pcolor(Y,Z,squeeze(log10(m.A(1,yind,zind)))'); shading flat; hold on; axis ij 25 | if exist('d','var') 26 | plot(d.y/1000,d.z/1000,'vk','MarkerFaceColor','k') 27 | end 28 | axis([min(m.cy(yind))/1000 max(m.cy(yind))/1000 u.zmin u.zmax]) 29 | title(['Cross Section Through 2D Resistivity Profile']); 30 | print_figure(['vertical_profile'],['Profile_Model_',m.niter]); 31 | 32 | 33 | 34 | y = m.cy(yind)/1000; 35 | x = ones(length(y),1).*m.cx(1)/1000; 36 | z = m.cz(zind)/1000; 37 | rho = squeeze(m.A(1,yind,zind)); 38 | 39 | end 40 | 41 | -------------------------------------------------------------------------------- /Model_Plotting/plot_cross_section_lat_long.m: -------------------------------------------------------------------------------- 1 | function plot_cross_section_lat_long 2 | % Function which takes a latitude, longitude, depth and resistivity values 3 | % and plots them as a cross-section 4 | % 5 | % Usage: plot_cross_section_lat_long 6 | % 7 | % Inputs: None 8 | % 9 | % For example, S3D can output a matfile which contains lat,long,z,rho 10 | % values for a cross-section. This matfile can then be loaded into this 11 | % function and plotted. Useful for debugging to make sure that S3D is 12 | % outputting the file correctly. 13 | % 14 | % This has not been thoroughly debugged. 15 | %% 16 | u = user_defaults; 17 | 18 | curdir = pwd; 19 | 20 | [filename, filepath]=uigetfile({'*.dat'},'Choose file which contains a cross section in longitude and latitude'); if filename == 0; return; end 21 | 22 | cd(filepath) 23 | section = load(filename); 24 | cd(curdir) 25 | 26 | z = unique(section(:,3)); 27 | nz = length(z); 28 | np = length(section); 29 | ndist = np/nz; %<<<<<<<-----This is incorrect 30 | 31 | plot(section(:,1),section(:,2),'.k') 32 | 33 | res_plot = reshape(section(:,4),ndist,nz)'; 34 | 35 | res_plot(res_plot==10^9)=NaN; 36 | 37 | figure(1); 38 | subplot(1,2,1) 39 | pcolor(1:ndist,z,res_plot); axis ij; hold on; axis equal 40 | 41 | if strcmp(u.gridlines,'off') 42 | shading flat 43 | end 44 | 45 | colormap(u.cmap); caxis(u.colim); 46 | add_rho_colorbar(u); 47 | 48 | xlabel(['Distance along Profile (km)']); 49 | ylabel('Depth (km)'); 50 | set(gca,'Layer','top') 51 | 52 | subplot(1,2,2) 53 | plot(section(:,1),section(:,2),'.k'); axis equal 54 | 55 | end 56 | -------------------------------------------------------------------------------- /Model_Plotting/plot_fwd_1d.m: -------------------------------------------------------------------------------- 1 | function plot_fwd_1d(fwd) 2 | 3 | T = 1./(fwd.freq_array); 4 | 5 | subplot(2,2,1); 6 | loglog(T,fwd.rho,'-k'); hold on 7 | grid on 8 | xlabel('Period (s)') 9 | ylabel('App Rho (Ωm)') 10 | set(gca,'FontSize',14) 11 | 12 | 13 | subplot(2,2,3); 14 | semilogx(T,fwd.phi,'-k'); hold on 15 | grid on 16 | xlabel('Period (s)') 17 | ylabel('Phase (deg)') 18 | set(gca,'FontSize',14) 19 | 20 | subplot(2,2,2); 21 | loglog(T,real(fwd.Z),'-k'); hold on 22 | grid on 23 | xlabel('Period (s)') 24 | ylabel('Real Impedance (Ω)') 25 | set(gca,'FontSize',14) 26 | 27 | subplot(2,2,4); 28 | loglog(T,imag(fwd.Z),'-k'); hold on 29 | grid on 30 | xlabel('Period (s)') 31 | ylabel('Imag Impedance (Ω)') 32 | set(gca,'FontSize',14) -------------------------------------------------------------------------------- /Model_Plotting/plot_mesh.m: -------------------------------------------------------------------------------- 1 | function plot_mesh(m,d) 2 | % Function to plot the mesh without using pcolor. This is useful to check that 3 | % stations are located in the cell center 4 | % 5 | % Usage: plot_mesh(m,d) 6 | % 7 | % 8 | 9 | set_figure_size(1); 10 | plot_mesh_option(m,d,1); 11 | plot_mesh_option(m,d,0); 12 | manual_legend('Cell Centers','.k','Cell Edges','-g','Station Locations','vr'); 13 | 14 | end 15 | 16 | function plot_mesh_option(m,d,flag) 17 | 18 | u = user_defaults; 19 | [L] = load_geoboundary_file_list; 20 | 21 | if flag 22 | subplot(1,2,1); 23 | else 24 | subplot(1,2,2); 25 | end 26 | 27 | plot(m.Xc(:)/1000,m.Yc(:)/1000,'.k'); hold on 28 | 29 | for i = 1:m.nx+1 30 | plot(m.X(i,:)/1000,m.Y(i,:)/1000,'-g'); 31 | end 32 | 33 | for i = 1:m.ny+1 34 | plot(m.X(:,i)/1000,m.Y(:,i)/1000,'-g'); 35 | end 36 | 37 | plot(d.x/1000,d.y/1000,'vr','MarkerFaceColor','r') 38 | plot_geoboundaries(L,d.origin,0) 39 | 40 | axis equal 41 | 42 | if flag 43 | %Set plotting limits 44 | if length(u.xylims)==4 %If xy limits were specified in user_defaults 45 | xind = nearestpoint(u.xylims(1),m.cx/1000,'previous'):nearestpoint(u.xylims(2),m.cx/1000,'next'); 46 | yind = nearestpoint(u.xylims(3),m.cy/1000,'previous'):nearestpoint(u.xylims(4),m.cy/1000,'next'); 47 | axlims = [u.xylims(3) u.xylims(4) u.xylims(1) u.xylims(2)]; 48 | 49 | else %If the limits specified are not a vector of numbers with length 4 then just take non-padding cells 50 | xind = m.npad(1)+1:m.nx-m.npad(1); 51 | yind = m.npad(2)+1:m.ny-m.npad(2); 52 | axlims = [sort([m.y(min(yind)) m.y(max(yind))]) sort([m.x(min(xind)) m.x(max(xind))])]/1000; 53 | end 54 | 55 | axis(axlims) 56 | title('Map of Mesh Survey Area'); 57 | else 58 | axis([m.y(1) m.y(end) m.x(1) m.x(end)]/1000) 59 | title('Map of Full Mesh Area') 60 | end 61 | set(gca,'Layer','top') 62 | xlabel('Distance East-West (km)') 63 | ylabel('Distance North-South (km)') 64 | 65 | end 66 | 67 | -------------------------------------------------------------------------------- /Model_Plotting/plot_slice_map.m: -------------------------------------------------------------------------------- 1 | function plot_slice_map(m,id,d) 2 | % 3 | % Function which plots a model slice in map view (lat-long) using m_map 4 | % 5 | % Usage: plot_slice_map(m,id,d) OR plot_slice_map(m,id) 6 | % 7 | % "m" is the model structure 8 | % "id" is the index of the slice to plot 9 | % "d" is the data structure and must be included in this function 10 | 11 | if id > m.nz 12 | warning('Layer index greater than number of layers! Plotting bottom layer.') 13 | id = m.nz; 14 | end 15 | 16 | u = user_defaults; 17 | [L] = load_geoboundary_file_list; 18 | [d] = set_map_projection(d); 19 | 20 | if ~isfield(m,'LON') 21 | error('Your model has not been converted to lat-long coordinates yet! See "link_model_data.m" for more info') 22 | end 23 | 24 | 25 | m_pcolor(m.LON,m.LAT,log10(m.A(:,:,id))); shading flat; hold on 26 | m_grid('box','fancy','xlabeldir','end','tickdir','in'); 27 | 28 | m_plot(d.loc(:,2),d.loc(:,1),'k.','markersize',12); 29 | plot_geoboundaries(L); 30 | 31 | if u.plot_contours %Plot contours as well if plot_contours flag is true 32 | if all(all(isnan(m.A(:,:,id))))~=1 33 | m_contour(m.LON,m.LAT,log10(m.A(:,:,id)),u.contours,'-k','ShowText',u.contour_text); 34 | end 35 | end 36 | 37 | colormap(u.cmap); caxis(u.colim); 38 | add_rho_colorbar(u); 39 | title(['Layer ',num2str(id),' | Depth = ',num2str(m.z(id)/1000),' to ',num2str(m.z(id+1)/1000),' km b.s.l.']); 40 | 41 | end -------------------------------------------------------------------------------- /Model_Plotting/plot_slice_menus.m: -------------------------------------------------------------------------------- 1 | function [is] = plot_slice_menus(m,is,d) 2 | %Function to plot model slice-by-slice by going to the next or previous 3 | %slice 4 | % 5 | % Usage: [is] = plot_slice_menus(m,is,d) OR plot_slice_menus(m,is) 6 | % 7 | % "m" is the model structure 8 | % "is" is the index to plot initially 9 | % "d" is an OPTIONAL data structure 10 | 11 | if ~exist('d','var') 12 | d = make_nan_data; 13 | end 14 | 15 | irun=1; 16 | while irun==1; %Secondary while loop: Exit loop by selecting slice 17 | clf 18 | plot_slice(m,is,d) 19 | 20 | %Option to specify slice by going deeper or shallower. Choose 21 | %the slice which best represents the feature to be edited. 22 | imenu=menu('','Next Slice (Deeper)','Previous Slice (Shallower)','Done'); 23 | 24 | if imenu==1 25 | is=is+1; 26 | if is>=m.nz 27 | is=m.nz; 28 | disp('Reached base of model. No deeper slice') 29 | end 30 | elseif imenu==2 31 | is=is-1; 32 | if is<1 33 | is=1; 34 | disp('Reached top of model. No shallower slice') 35 | end 36 | else 37 | return 38 | end 39 | end 40 | 41 | end 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mtcode 2 | 3 | Collection of MATLAB scripts written and maintained by current and past members of the University of Alberta Magnetotelluric group lead by Martyn Unsworth. The repository is currently maintained by Darcy Cordell and Benjamin Lee. 4 | 5 | See the Documentation Folder for detailed description of how to use the scripts, the organizational structure of the scripts, and their functionality. 6 | 7 | If you use these scripts please provide an acknowledgement: 8 | 9 | Unsworth, M.J., Cordell, D., Lee, B., 2022. mtcode: A repository of MATLAB scripts for magnetotelluric data analysis, data editing, model building, and model viewing, doi:10.5281/zenodo.6784201 10 | 11 | [![DOI](https://zenodo.org/badge/277923435.svg)](https://zenodo.org/badge/latestdoi/277923435) 12 | -------------------------------------------------------------------------------- /Utils/Figures/add_rho_colorbar.m: -------------------------------------------------------------------------------- 1 | function add_rho_colorbar(u) 2 | 3 | hcb = colorbar; 4 | set(hcb, 'Ticks', get(hcb,'Ticks')); % need this to ensure number of ticks doesn't change when resizing figure 5 | if strcmp(u.clabel,'log') 6 | hcb.Label.String = 'log10 ( Resistivity \Omega m )'; 7 | elseif strcmp(u.clabel,'linear') 8 | set(hcb,'TickLabels',num2cell(round(10.^(hcb.Ticks),2,'significant'))') 9 | hcb.Label.String = 'Resistivity (\Omega m)'; 10 | end 11 | 12 | end -------------------------------------------------------------------------------- /Utils/Figures/logerrorbar.m: -------------------------------------------------------------------------------- 1 | function [h,g] = logerrorbar(X,Y,dY,linetype1,linetype2) 2 | %Function to plot error bars on log-log plot and avoid negative numbers 3 | % 4 | % Usage: h = logerrorbar(X,Y,dY,linetype1,linetype2) 5 | % 6 | % X = x data 7 | % Y = y data 8 | % dY = y error 9 | % linetype1 = string for plotting linetype of data. Example: linetype = '-.r' 10 | % linetype2 = string for plotting the linetype of the errorbar lines (usually should be '-' with some color). 11 | %% 12 | 13 | h = loglog(X,Y,linetype1,'LineWidth',1); hold on 14 | 15 | lower = Y-dY; 16 | lower(lower<=0) = 10^-40; 17 | g = plot([X X]',[lower Y+dY]',linetype2,'LineWidth',1); hold on %Plot vertical error bar 18 | 19 | 20 | set(gca, 'YScale', 'log') 21 | set(gca, 'XScale', 'log') 22 | 23 | 24 | end %END LOGERRORBAR -------------------------------------------------------------------------------- /Utils/Figures/manual_legend.m: -------------------------------------------------------------------------------- 1 | function h = manual_legend(varargin) 2 | % 3 | % Function to produce a manual legend that does not depend on the current 4 | % plot. 5 | % 6 | % Usage: manual_legend(varargin) 7 | % 8 | % Inputs: varargin is a list of linetype and label pairs as strings 9 | % OR a list of linecolor RGB triples and label strings. 10 | % 11 | % Example #1: 12 | % manual_legend('Data #1','or','Data #2','-k','Data #3','*m') 13 | % 14 | % This will produce a legend which shows red circles, black lines, and 15 | % magenta stars with their corresponding labels. 16 | % 17 | % Example #2: 18 | % manual_legend('Data #1',[1 0 0 ],'Data #2',[0.2 1 0.5]) 19 | % 20 | % This will produce a legend which shows red dots, and green-blue dots. 21 | % Note this option will always show the legend with dots as the linetype 22 | % 23 | % 24 | % 25 | 26 | % 27 | 28 | numel = length(varargin)/2; 29 | 30 | if round(numel)-numel ~= 0 31 | error('Error on Input of Manual Legend: Must have linetype and legend label pairs as strings') 32 | end 33 | 34 | h = zeros(numel,1); legend_string = {}; 35 | for i = 1:numel 36 | legend_string{i} = varargin{i*2-1}; 37 | 38 | if ischar(varargin{i*2}) 39 | h(i) = plot(NaN,NaN,varargin{i*2},'LineWidth',3); hold on 40 | elseif isnumeric(varargin{i*2}) && length(varargin{i*2})==3 41 | h(i) = plot(NaN,NaN,'.','Color',varargin{i*2},'LineWidth',3); hold on 42 | else 43 | error('You must input either a MATLAB-recognized string specifying the color/linetype (e.g. -k) or a 3x1 vector of colors (e.g. [0 0.5 0.2])') 44 | end 45 | end 46 | 47 | legend(h, legend_string,'AutoUpdate','off','Interpreter','none'); -------------------------------------------------------------------------------- /Utils/Figures/plot_rectangular_fault_plane.m: -------------------------------------------------------------------------------- 1 | function P = plot_rectangular_fault_plane(strike, dip, width, length,location) 2 | % Function which plots a rectangular fault plane in 3-D space 3 | % 4 | % Inputs 5 | % 6 | % strike: strike of fault in degrees (right-hand rule) 7 | % dip: dip of the fault in degrees (right-hand rule) 8 | % width: width of the fault specified in axis units (e.g. if you are 9 | % plotting in lat-long, then this should be in lat-long degrees) 10 | % length: length of the fault specified in axis units 11 | % location: The location of the fault in 3-D space specified as a vector [Px, Py, Pz] 12 | % The location specifies the corner of the prism opposite to the quadrant 13 | % of the strike. E.g. for strike = 45 (NE quadrant), the location specifies 14 | % the SW corner of the rectangle; for strike = 75 (SE quadrant), the 15 | % location specifies the NW corner of the rectangle. 16 | % 17 | % Note the "width" is defined as the dipping side of the rectangular plane 18 | % while the "length" is the side parallel to the surface. Width can be 19 | % larger than length. 20 | % 21 | % Outputs 22 | % 23 | % P is a 4x3 vector specifying the corners of the rectangle A,B,C,D 24 | 25 | A = location; % Pivot point at the surface 26 | 27 | H = width*sind(strike+90); 28 | V = width*cosd(strike+90); 29 | Z = -width*sind(dip); 30 | 31 | B = [length*sind(strike) length*cosd(strike) 0]+A; 32 | C = [length*cosd(90-strike)+H length*sind(90-strike)+V Z]+A; 33 | D = [width*sind(strike+90) width*cosd(strike+90) -width*sind(dip)]+A; 34 | 35 | P = [A; B; C; D]; 36 | 37 | figure(1); p = patch(P(:,1),P(:,2),P(:,3),'red'); 38 | xlabel('EW Distance (km)');ylabel('NS Distance (km)');zlabel('Elevation (km b.s.l.)'); %axis equal 39 | axis equal 40 | 41 | 42 | end 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Utils/Figures/rose_geog.m: -------------------------------------------------------------------------------- 1 | function rose_geog(E,nbins,rmax,col) 2 | % 3 | % Function to plot a CORRECT rose diagram (with the proper polygons filled 4 | % in). The original rose diagram function often did not fill the polygons 5 | % correctly. 6 | % 7 | % Improved by MJU. 8 | % 9 | % Based on 10 | % http://www.mathworks.com/matlabcentral/fileexchange/33664-earthrose/content/earth_rose.m 11 | % Cameron Sparr cameronsparr@gmail.com 12 | % 13 | % Usage: rose_geog(E,nbins,rmax,col) 14 | % 15 | % Inputs: 16 | % E: the angle data to bin in a circular histogram (in degrees) 17 | % nbins: the number of bins to bin the data 18 | % rmax: The maximum tick to plot on the radial scale (e.g. the radius 19 | % of the rose diagram) 20 | % col: The color to fill the polygons 21 | % 22 | 23 | % edited BL 2020 - prepare azimuths separately for phase tensor and 24 | % induction arrows in invoking functions - focus on ploting in this 25 | % function 26 | E = -E; %function takes angle CCW but we want CW from north 27 | E = E*pi/180; % Convert to radians 28 | 29 | if nargin > 1 30 | % Following added by MJU to fill sectors 31 | polar([NaN, NaN],[0., rmax]) % Plot vector to control radial scale 32 | set(findobj(gca,'Type','line'),'Color','k'); 33 | hold on 34 | polar([NaN, NaN],[0., rmax]) 35 | set(findobj(gca,'Type','line'),'Color','k'); 36 | [tout, rout] = rose(E,nbins); 37 | polar(tout, rout); 38 | [xout, yout] = pol2cart(tout, rout); 39 | set(gca, 'nextplot', 'add'); 40 | % patch(xout, yout, col); % this doesn't work, need to plot each bin separately 41 | for i = 1:nbins 42 | patch(xout(4*(i-1)+1:4*i), yout(4*(i-1)+1:4*i), col); 43 | end 44 | else 45 | rose(E); 46 | end 47 | 48 | hHiddenText = findall(gca,'type','text'); 49 | Angles = 0 : 30 : 330; 50 | hObjToDelete = zeros( length(Angles)-4, 1 ); 51 | k = 0; 52 | for ang = Angles 53 | hObj = findall(hHiddenText,'string',num2str(ang)); 54 | switch ang 55 | case 0 56 | set(hObj,'string','E','HorizontalAlignment','Left'); 57 | case 90 58 | set(hObj,'string','N','VerticalAlignment','Bottom'); 59 | case 180 60 | set(hObj,'string','W','HorizontalAlignment','Right'); 61 | case 270 62 | set(hObj,'string','S','VerticalAlignment','Top'); 63 | otherwise 64 | k = k + 1; 65 | if ~isempty(hObj) 66 | hObjToDelete(k) = hObj; 67 | end 68 | end 69 | end 70 | delete( hObjToDelete(hObjToDelete~=0) ); 71 | 72 | end -------------------------------------------------------------------------------- /Utils/Figures/set_figure_size.m: -------------------------------------------------------------------------------- 1 | function [fig] = set_figure_size(n) 2 | % 3 | % A function to set a standard figure size based on the computer's 4 | % screensize. 5 | % 6 | % Usage: [fig] = set_figure_size(n) 7 | % 8 | % Input: 9 | % n: the figure number 10 | % 11 | % Output: 12 | % fig: the figure handle 13 | % 14 | 15 | 16 | if exist('n','var')~=1 17 | n = 1; 18 | end 19 | 20 | screensize=get(groot,'Screensize'); 21 | fig=figure(n); 22 | clf 23 | set(fig,'Position',[0.1*screensize(3) 0.1*screensize(4) 0.8*screensize(3) 0.8*screensize(4)]) 24 | -------------------------------------------------------------------------------- /Utils/Figures/set_inset_position.m: -------------------------------------------------------------------------------- 1 | function set_inset_position(ax,h_inset,loc) 2 | % Set Rose diagram inset location (top left, top right, bottom left or 3 | % bottom right) 4 | % Inputs: 5 | % ax = position of the main figure, retrieved before function call with ax=get(main_fig,'Position'); 6 | % h_inset = handle of the axes for the inset figure 7 | % loc = string or xy coordinate location of inset (from user_defaults) 8 | % 9 | % this function is currently only called by plot_phase_tensor_map and 10 | % plot_induction_vector_map 11 | 12 | u = user_defaults; 13 | inset_size=u.inset_size*.7; 14 | 15 | if ~isnumeric(loc) 16 | switch loc 17 | case 'SW' 18 | set(h_inset,'Position', [ax(1) ax(2) inset_size inset_size]) % SW 19 | case 'SE' 20 | set(h_inset,'Position', [ax(1)+ax(3)-inset_size ax(2) inset_size inset_size]) % SE 21 | case 'NE' 22 | set(h_inset,'Position', [ax(1)+ax(3)-inset_size ax(2)+ax(4)-inset_size inset_size inset_size]) % NE 23 | case 'NW' 24 | set(h_inset,'Position', [ax(1) ax(2)+ax(4)-inset_size inset_size inset_size]) % NW 25 | otherwise 26 | disp('Unrecognized format of u.inset_loc. Check your user_defaults file') 27 | set(h_inset,'Position', [ax(1) ax(2)+ax(4)-inset_size inset_size inset_size]) % NW 28 | end 29 | elseif isnumeric(loc) && numel(loc)==2 30 | set(h_inset,'Position', [loc(1) loc(2) inset_size inset_size]) % custom 31 | else 32 | disp('Unrecognized format of u.inset_loc. Check your user_defaults file') 33 | set(h_inset,'Position', [ax(1) ax(2)+ax(4)-inset_size inset_size inset_size]) % NW 34 | end 35 | 36 | end -------------------------------------------------------------------------------- /Utils/Mapping/dms2deg.m: -------------------------------------------------------------------------------- 1 | function[decimal] = dms2deg(deg,mini,sec) 2 | 3 | % Function to convert degree, minute, second format into 4 | % decimal degrees format 5 | 6 | % Greg Nieuwenhus, 2012 7 | 8 | decimal=deg+(mini/60)+(sec/3600); 9 | 10 | -------------------------------------------------------------------------------- /Utils/Mapping/download_srtm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Utils/Mapping/download_srtm.m -------------------------------------------------------------------------------- /Utils/Mapping/geo2utm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darcycordell/mtcode/b420c9b68cc9903b445432f993d15ef41ab32947/Utils/Mapping/geo2utm.m -------------------------------------------------------------------------------- /Utils/Mapping/get_projection.m: -------------------------------------------------------------------------------- 1 | function MAP_PROJECTION = get_projection 2 | 3 | global MAP_PROJECTION -------------------------------------------------------------------------------- /Utils/Mapping/haversine.m: -------------------------------------------------------------------------------- 1 | function [d,theta] = haversine(lat1,lon1,lat2,lon2) 2 | %Function which calculates the distance between two latitude and longitude 3 | %points on the Earth's surface 4 | % 5 | % Usage: [d,theta] = haversine(lat1,lon1,lat2,lon2) 6 | % 7 | % Inputs: (lat1,lon1) is the first point in degrees 8 | % (lat2,lon2) is the second point in degrees 9 | % 10 | % Outputs: 11 | % d: The distance between (lat1,lon1) and (lat2,lon2) in kilometers' 12 | % theta: The angle between the two points in degrees 13 | 14 | R = 6378.1; %Radius of the Earth 15 | rad = pi/180; 16 | 17 | dlat = lat2*rad-lat1*rad; 18 | dlon = lon2*rad-lon1*rad; 19 | 20 | a = sin(dlat/2).^2 + cos(lat1*rad).*cos(lat2*rad).* sin(dlon/2).^2; 21 | c = 2*atan2(sqrt(a), sqrt(1-a)); 22 | d = R*c; 23 | 24 | theta = atan2(sin(dlon)*cos(lat2*rad),cos(lat1*rad)*sin(lat2*rad)-sin(lat1*rad)*cos(lat2*rad)*cos(dlon))/rad; -------------------------------------------------------------------------------- /Utils/Mapping/haversine_d.m: -------------------------------------------------------------------------------- 1 | function [lat2,lon2] = haversine_d(bearing,d,lat1,lon1) 2 | %Function which calculates the final latitude and longitude after travelling a 3 | %distance, d, along a bearing from a starting latitude and longitude. 4 | % 5 | % Usage: [lat2, lon2] = haversine_d(bearing,d,lat1,lon1) 6 | % 7 | %Bearing is in degrees. 8 | %d is distance in kilometers 9 | %Latitude and longitude are given in degrees 10 | 11 | 12 | R = 6378.1; %Radius of the Earth 13 | rad = pi/180; 14 | 15 | bearing = bearing*rad; 16 | 17 | lat1 = lat1*rad; %Current lat point converted to radians 18 | lon1 = lon1*rad; %Current long point converted to radians 19 | 20 | lat2 = asin(sin(lat1).*cos(d/R) + cos(lat1).*sin(d/R).*cos(bearing)); 21 | lon2 = lon1 + atan2(sin(bearing).*sin(d/R).*cos(lat1),cos(d/R)-sin(lat1).*sin(lat2)); 22 | 23 | lat2 = lat2/rad; 24 | lon2 = lon2/rad; 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Utils/Mapping/kml2geo.m: -------------------------------------------------------------------------------- 1 | function kml2geo(kmlfile,geofile) 2 | % Script to read kmlfile with placemarks, and output longitude and latitude 3 | % into MTcode style geofile 4 | % 5 | % Usage: kml2geo(kmlfile,geofile) 6 | % 7 | % Inputs: kmlfile = name of kml file, geofile = name of output file 8 | % can also hardcode file names at top of function when using 0 inputs 9 | % 10 | % only tested with kml file output from Google Earth 11 | if nargin == 0 12 | kmlfile = 'west shore.kml'; 13 | geofile = 'Kinbasket_Lake_west_coords.txt'; % name of output file 14 | end 15 | %% 16 | 17 | fid = fopen(kmlfile); 18 | 19 | nlon = 0; 20 | nlat = 0; 21 | filetype = 'Point'; 22 | while 1 23 | 24 | tline = fgetl(fid); 25 | if ~ischar(tline), break, end 26 | tline = strtrim(tline); 27 | 28 | if strfind(tline,'