├── Code ├── FEMIC_DOI.m ├── FEMIC_DOII.asv ├── FEMIC_DOII.m ├── FEMIC_FWDlayers.m ├── FEMIC_JacobianMdl.m ├── FEMIC_Manual.pdf ├── FEMIC_cal.m ├── FEMIC_corner.m ├── FEMIC_discrep.m ├── FEMIC_forward2D.m ├── FEMIC_gcorner.m ├── FEMIC_inverse1D.m ├── FEMIC_inverse2D.asv ├── FEMIC_inverse2D.m ├── FEMIC_inverse3D.m ├── FEMIC_inverse4D.m ├── FEMIC_inverse5.fig ├── FEMIC_inverse5.m ├── FEMIC_maxentropy.m ├── FEMIC_plotINVinterim.m ├── FEMIC_svd.m ├── FEMIC_tost.m ├── FEMIC_tost1.m ├── FEMIC_tost2.m ├── FEMIC_tost21.m ├── FEMIC_tost22.m ├── FEMIC_tost3.m ├── Figure1-model and data.fig ├── GEM2FEM.m ├── J0_120pt.mat ├── J0_61pt.mat ├── J1_140pt.mat ├── J1_47pt.mat ├── Last1D.m ├── Last2D.m ├── R2.dat ├── bicgstb.m ├── calcHxx.m ├── calcHzz.m ├── calcWTW.m ├── calcrTEsens.m ├── cubicSpline.m ├── fdem1dfwd.m ├── fdem1dfwd2.m ├── fdemCal.m ├── file ├── getLambda.m ├── getcontourlines.m ├── grad.m ├── grad2d.m ├── grad3D.m ├── init.dat ├── ipcg.m ├── kron3.m ├── kron33.m ├── matsol.m ├── mkvc.m ├── modelInv_parms.dat ├── nearestneighbour.m ├── new_calibration.m ├── newgradient.m ├── precg.m ├── progressbar.m ├── result.mat ├── sense.dat ├── smooth_mtx_surface4444.m ├── start.fig └── start.m ├── Data-sets ├── Data ├── Field-WY │ ├── Initial model.dat │ ├── Input_WY_data.dat │ ├── READ ME.txt │ └── data └── Synthetic │ ├── Input_femic.dat │ ├── Input_femic_initial.dat │ ├── READ ME.txt │ ├── Real_model.tif │ ├── TEST.tif │ └── data ├── Figure11 ├── Figure 11.kmz └── KMZ └── README.md /Code/FEMIC_DOI.m: -------------------------------------------------------------------------------- 1 | function [doi]=FEMIC_DOI(d,pobs,sigma,f,r,muv,err_tol,max_iter,q,vall,perc) 2 | fprintf('****** STARTING MAXIMUM DOI ESTIMATION ******\n'); 3 | [m n]=size(pobs);sigma=sigma(:,1); 4 | parfor i=1:n-1 5 | po(i)=abs(sum(pobs(:,i))-sum(pobs(:,i+1)))\min(min([sum(pobs(:,i)) sum(pobs(:,i+1))])); 6 | end 7 | po(po==inf)=0;po=100.*po; 8 | ee=find(po>perc);dff=n-length(ee); 9 | if dff>1 && min(ee)~=1 && max(ee)~=n 10 | ff=[1 min(ee)-1 ee max(ee)+1 n];%ff(length(ff)+1:length(ee)+dff)=[ee max(ee)+1 n]; 11 | else 12 | ff=[ee]; 13 | end 14 | ff=unique(ff); 15 | if isempty(ff) || length(ff)<=3 16 | redpobs=pobs(:,[1 floor(n/3) floor(n/2) n]); 17 | ff =[1 floor(n/3) floor(n/2) n]; 18 | else 19 | redpobs=pobs(:,ff); 20 | end 21 | params=40*ones(length(f),1);%round((min(min(redpobs)) + max(max(redpobs)))/2)*ones(length(f),1); 22 | [sa ta]=size(redpobs); 23 | %model1=zeros(sa,ta); 24 | parfor u=1:ta 25 | [model1, muh_final, rms_error, G]=FEMIC_tost22(params,d,redpobs(:,u),sigma,f,r,muv,... 26 | err_tol,max_iter,q); 27 | model11(:,u)=model1; 28 | end 29 | params2=60*ones(length(f),1);%abs(params(1)-round(max(max(redpobs))/2))*ones(length(f),1); %model2=zeros(sa,ta); 30 | parfor u=1:ta 31 | [model2, muh_final, rms_error, G]=FEMIC_tost22(params2,d,redpobs(:,u),sigma,f,r,muv,... 32 | err_tol,max_iter,q); 33 | model22(:,u)=model2; 34 | end 35 | R=abs(model11-model22)./min(min(abs(params-params2))); 36 | [u y]=size(R);dd=cumsum(d); 37 | for i=1:y 38 | 39 | bl=find(R(1:u,i)>0.2); 40 | to(i)=dd(bl(1)); 41 | end 42 | ap=1:n;%rq=length(ff);ff(rq+1)=n;to(rq+1)=to(1); 43 | doi=interp1(ff,to,ap); 44 | fprintf('****** END OF DOI ESTIMATION ******\n'); 45 | fprintf('****** STARTING THE INVERSION ******\n'); -------------------------------------------------------------------------------- /Code/FEMIC_DOII.asv: -------------------------------------------------------------------------------- 1 | function [doi, model1,model2]=FEMIC_DOII(Ma,S,el,pobs,sigma,f,r,muv,err_tol,max_iter,q,vall,perc,sx,sz,wta,d,pmin,pmax,coords) 2 | fprintf('****** STARTING MAXIMUM DOI ESTIMATION ******\n'); 3 | pobs=reshape(pobs,length(S.freq),length(pobs(:))/length(S.freq)); 4 | sigma=reshape(sigma,length(S.freq),length(pobs(:))/length(S.freq)); 5 | [m, n]=size(pobs);%sigma=sigma(:,1); 6 | parfor i=1:n-1 7 | po(i)=abs(sum(pobs(:,i))-sum(pobs(:,i+1)))\min(min([sum(pobs(:,i)) sum(pobs(:,i+1))])); 8 | end 9 | po(po==inf)=0;po=100.*po; 10 | ee=find(po>perc);dff=n-length(ee); 11 | if dff>1 && min(ee)~=1 && max(ee)~=n 12 | ff=[1 min(ee)-1 ee max(ee)+1 n];%ff(length(ff)+1:length(ee)+dff)=[ee max(ee)+1 n]; 13 | else 14 | ff=[ee]; 15 | end 16 | ff=unique(ff); 17 | if isempty(ff) || length(ff)<=3 18 | redpobs=pobs(:,[1 floor(n/3) floor(n/2) floor(2*n/3) n]); 19 | ff =[1 floor(n/3) floor(n/2) floor(2*n/3) n]; 20 | rsigma=sigma(:,[1 floor(n/3) floor(n/2) floor(2*n/3) n]); 21 | else 22 | redpobs=pobs(:,ff); 23 | rsigma=sigma(:,ff); 24 | end 25 | [m2, n2]=size(redpobs); 26 | Ma.thk=2*ones(10,1);Ma.k=10;Ma.chie=zeros(10,1);Ma.chim=zeros(10,1); 27 | Ma.con=log10(1/200)*ones(length(Ma.thk),n2);wta=ones(length(Ma.thk),n2);%round((min(min(redpobs)) + max(max(redpobs)))/2)*ones(length(f),1); 28 | 29 | muv=1; 30 | [model1, muh_final, rms_error2, G]=[p_final, muh_final, rms_error, G,sense,cell_sensy]=FEMIC_tost2(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords,sens,cell_sens);%FEMIC_tost21(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords) 31 | Ma.con=log10(1/100)*ones(Ma.k,n2);%abs(params(1)-round(max(max(redpobs))/2))*ones(length(f),1); %model2=zeros(sa,ta); 32 | [model2, muh_final, rms_error2, G]=FEMIC_tost21(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords) 33 | 34 | R=abs(model1-model2)./abs(log10(1/200)-log10(1/100));dlmwrite('R.dat',R);dlmwrite('m1.dat',model1);dlmwrite('m2.dat',model2); 35 | [u y]=size(R);dd=cumsum(Ma.thk); 36 | for i=1:y 37 | b=find(R(:,i)<0.2); 38 | if isempty(b) 39 | to(i)=dd(1); 40 | else 41 | ba=find(diff(b)>1);if isempty(ba);to(i)=dd(2);else to(i)=dd(ba(1));end 42 | 43 | end 44 | 45 | end 46 | ap=1:n;%rq=length(ff);ff(rq+1)=n;to(rq+1)=to(1); 47 | doi=interp1(ff,to,ap);dlmwrite('doi.dat',doi);dlmwrite('ff.dat',ff); 48 | 49 | fprintf('****** END OF DOI ESTIMATION ******\n'); 50 | fprintf('****** STARTING THE INVERSION ******\n'); -------------------------------------------------------------------------------- /Code/FEMIC_DOII.m: -------------------------------------------------------------------------------- 1 | function [model1,model2,ff,Ma]=FEMIC_DOII(Ma,S,el,pobs,sigma,f,r,muv,err_tol,max_iter,q,vall,perc,sx,sz,wta,d,pmin,pmax,coords) 2 | fprintf('****** STARTING MAXIMUM DOI ESTIMATION ******\n'); 3 | pobs=reshape(pobs,length(S.freq),length(pobs(:))/length(S.freq)); 4 | sigma=reshape(sigma,length(S.freq),length(pobs(:))/length(S.freq)); 5 | [m, n]=size(pobs);%sigma=sigma(:,1); 6 | parfor i=1:n-1 7 | po(i)=abs(sum(pobs(:,i))-sum(pobs(:,i+1)))\min(min([sum(pobs(:,i)) sum(pobs(:,i+1))])); 8 | end 9 | po(po==inf)=0;po=100.*po; 10 | ee=find(po>perc);dff=n-length(ee); 11 | if dff>1 && min(ee)~=1 && max(ee)~=n 12 | ff=[1 min(ee)-1 ee max(ee)+1 n];%ff(length(ff)+1:length(ee)+dff)=[ee max(ee)+1 n]; 13 | else 14 | ff=[ee]; 15 | end 16 | ff=unique(ff); 17 | if isempty(ff) || length(ff)<=3 18 | redpobs=pobs(:,[1 floor(n/3) floor(n/2) floor(2*n/3) n]); 19 | ff =[1 floor(n/3) floor(n/2) floor(2*n/3) n]; 20 | rsigma=sigma(:,[1 floor(n/3) floor(n/2) floor(2*n/3) n]); 21 | else 22 | redpobs=pobs(:,ff); 23 | rsigma=sigma(:,ff); 24 | end 25 | [m2, n2]=size(redpobs); 26 | Ma.thk=(Ma.thk(1)/2)*ones(2*length(Ma.thk),1);Ma.k=length(Ma.thk);Ma.chie=zeros(Ma.k,1);Ma.chim=zeros(Ma.k,1); 27 | Ma.con=log10(1/50)*ones(length(Ma.thk),n2);wta=ones(length(Ma.thk),n2);%round((min(min(redpobs)) + max(max(redpobs)))/2)*ones(length(f),1); 28 | 29 | muv=10; 30 | [model1, muh_final, rms_error2, G]=FEMIC_tost2(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords,0,0);%FEMIC_tost21(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords) 31 | Ma.con=log10(1/100)*ones(Ma.k,n2);%abs(params(1)-round(max(max(redpobs))/2))*ones(length(f),1); %model2=zeros(sa,ta); 32 | [model2, muh_final, rms_error2, G]=FEMIC_tost2(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords,0,0);%FEMIC_tost21(Ma,S,el,redpobs,rsigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords) 33 | 34 | R=abs((model1)-(model2))./abs(log10(1/50)-log10(1/100));dlmwrite('R2.dat',R);d 35 | [u y]=size(R);dd=cumsum(Ma.thk); 36 | for i=1:y 37 | b=find(R(:,i)<0.2); 38 | if isempty(b) 39 | to(i)=dd(1); 40 | else 41 | ba=find(diff(b)>1);if isempty(ba);to(i)=dd(b(end));elseif length(ba)>=1 to(i)=dd(b(ba)+1); end 42 | 43 | end 44 | 45 | end 46 | ap=1:n;%rq=length(ff);ff(rq+1)=n;to(rq+1)=to(1); 47 | doi=interp1(ff,to,ap); 48 | 49 | fprintf('****** END OF DOI ESTIMATION ******\n'); 50 | %fprintf('****** STARTING THE INVERSION ******\n'); -------------------------------------------------------------------------------- /Code/FEMIC_FWDlayers.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/FEMIC_FWDlayers.m -------------------------------------------------------------------------------- /Code/FEMIC_JacobianMdl.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/FEMIC_JacobianMdl.m -------------------------------------------------------------------------------- /Code/FEMIC_Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/FEMIC_Manual.pdf -------------------------------------------------------------------------------- /Code/FEMIC_cal.m: -------------------------------------------------------------------------------- 1 | function [rawGem, calGem, filtGem]=FEMIC_cal(dcale,dobsy,f,r,q,vall) 2 | %dcal = prdGEM; % data you are calibrating to (predicted response to the DC model) 3 | %dobs = obsGEM; % data you want to calibrate (the observed GEM) 4 | isOpen = matlabpool('size') > 0;%plotdoi=0; 5 | fprintf('****** STARTING THE RAW DATA FILTERING AND CALIBRATION PROCESS ******\n'); 6 | if isOpen==0 7 | matlabpool('local',vall) 8 | end 9 | m=mean(dcale(:,4)); 10 | parfor ii=1:length(f) 11 | depth(ii)=503/sqrt(f(ii)*(m*1000.)); %estimate depth of penetration for frequency 12 | d2(:,ii)=abs(dcale(:,3)-depth(ii)); %find difference between depth of resistivity and depth of EM 13 | ff=min(d2(:,ii)) %which resisitivity depth is closest to the EM depth 14 | fdepth(:,ii)=find(d2(:,ii)==ff); %find all resistivity measurements that correspond to that depth 15 | end 16 | fdepth=fdepth';fdepth=fdepth(:); 17 | dcale2(:,1)=dcale(fdepth,1); 18 | dcale2(:,2)=dcale(fdepth,2); 19 | dcale2(:,3)=dcale(fdepth,3); 20 | dcale2(:,4)=dcale(fdepth,4);dcale=dcale2; 21 | xx=(dcale(:,1));yy=(dcale(:,2));dd=dcale(:,3); 22 | dcall=dcale(:,4); 23 | dcali=reshape(dcall,length(f),length(dd)/length(f)); 24 | warning off 25 | dobss=dobsy(:,8); 26 | xx2=dobsy(:,1); 27 | yy2=dobsy(:,2); 28 | rawGem=dobss; 29 | coor1=[xx,yy]; 30 | coor2=[xx2,yy2]; 31 | [m n]=size(coor1); 32 | [ma na]=size(coor2); 33 | 34 | %finding distance 35 | for i=1:m 36 | parfor j=1:ma 37 | bo(j,i)=sum(abs(coor1(i,:)-coor2(j,:))); 38 | end 39 | end 40 | 41 | [mm nn]=size(bo); 42 | for ii=1:nn 43 | ba=bo(:,ii); 44 | boo(ii)=min(find(ba==min(ba))); 45 | end 46 | dcali=dcali(:); 47 | dcali2=reshape(dcali,length(f),length(dcali)/length(f)); 48 | 49 | [dcal]=FEMIC_forward2D(dcali2,depth,vall); 50 | dcal=dcal'; 51 | dobsa=dobss(boo); 52 | dobs=reshape(dobsa,length(f),length(dobsa)/length(f)); 53 | dobs=dobs'; 54 | ns = size(dobs,1); % soundings 55 | nf = size(dobs,2); % frequencies 56 | % initial values 57 | G = ones(1,nf); % gain 58 | B = zeros(1,nf); % bias 59 | dprd = (dcal + repmat(B,ns,1))*diag(G); 60 | 61 | wd = ones(1,nf); % enter 1/sigma values 62 | wm = [1 1]; % G, B 63 | 64 | % build block matrices - kind of klugey for now... 65 | for i=1:nf 66 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 67 | A(i).D = dobs(:,i) - dprd(:,i); 68 | A(i).Wd = wd(i)*eye(ns); 69 | A(i).Wm = diag(wm); 70 | A(i).m = [G(i);B(i)]; 71 | end 72 | J = blkdiag(A.J); 73 | D = blkdiag(A.D); 74 | Wd = blkdiag(A.Wd); 75 | Wm = blkdiag(A.Wm); 76 | m = blkdiag(A.m); 77 | m0 = blkdiag(A.m); 78 | 79 | 80 | %% solve 81 | for n = 1:10 82 | 83 | H = J'*Wd'*Wd*J + Wm'*Wm; 84 | r = J'*Wd'*D + Wm'*Wm*(m-m0); 85 | 86 | % calculate update 87 | dm = H\r; 88 | m = m + dm; 89 | G = G + diag(dm(1:2:end,:)).'; 90 | B = B + diag(dm(2:2:end,:)).'; 91 | 92 | % update predicted & calibrated data 93 | dprd = (dcal + repmat(B,ns,1))*diag(G); 94 | dcor = dobs*diag(1./G) - repmat(B,ns,1); 95 | calGem=dcor; 96 | 97 | % update block matrices - kind of klugey for now... 98 | for i=1:nf 99 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 100 | A(i).D = dobs(:,i) - dprd(:,i); 101 | end 102 | J = blkdiag(A.J); 103 | D = blkdiag(A.D); 104 | 105 | % misfit 106 | err(n,:) = diag(D'*(Wd'*Wd)*D); 107 | 108 | end 109 | dcor=dcor'; 110 | dcor2=dcor(:); 111 | dobss(boo)=dcor2; 112 | %dlmwrite('dob.dat',dobss); 113 | 114 | 115 | %% PCA filter 116 | %dobss(ffo)=dcor2; 117 | dcorr=reshape(dobss,length(f),length(dobss)/length(f));%length(find(xx2==xx2(1))),length(dobss)/length(find(xx2==xx2(1))));dcorr=dcorr'; 118 | m = mean(dcorr.',2);ns=length(f); 119 | M = repmat(m,1,ns); 120 | [u,s,v] = svd(dcorr.' - M); 121 | lp = u(:,1)*u(:,1)'*(dcorr.'-M) + M; filtGem=lp;% 1st component only 122 | Filtered_data=dobsy;Filtered_data(:,8)=lp(:); 123 | %dlmwrite('Filtered_data.dat',Filtered_data,'precision','%12.5f'); 124 | dlmwrite('Filtered_data.dat',Filtered_data); 125 | fprintf('****** THE RAW DATA HAS BEEN FILTERED AND CALIBRATED SUCCESSFULLY ******\n'); 126 | -------------------------------------------------------------------------------- /Code/FEMIC_corner.m: -------------------------------------------------------------------------------- 1 | function [k_corner,info] = FEMIC_corner(rho,eta,fig) 2 | %CORNER Find corner of discrete L-curve via adaptive pruning algorithm. 3 | % 4 | % [k_corner,info] = corner(rho,eta,fig) 5 | % 6 | % Returns the integer k_corner such that the corner of the log-log 7 | % L-curve is located at ( log(rho(k_corner)) , log(eta(k_corner)) ). 8 | % 9 | % The vectors rho and eta must contain corresponding values of the 10 | % residual norm || A x - b || and the solution's (semi)norm || x || 11 | % or || L x || for a sequence of regularized solutions, ordered such 12 | % that rho and eta are monotonic and such that the amount of 13 | % regularization decreases as k increases. 14 | % 15 | % The second output argument describes possible warnings. 16 | % Any combination of zeros and ones is possible. 17 | % info = 000 : No warnings - rho and eta describe a discrete 18 | % L-curve with a corner. 19 | % info = 001 : Bad data - some elements of rho and/or eta are 20 | % Inf, NaN, or zero. 21 | % info = 010 : Lack of monotonicity - rho and/or eta are not 22 | % strictly monotonic. 23 | % info = 100 : Lack of convexity - the L-curve described by rho 24 | % and eta is concave and has no corner. 25 | % 26 | % The warnings described above will also result in text warnings on the 27 | % command line. Type 'warning off Corner:warnings' to disable all 28 | % command line warnings from this function. 29 | % 30 | % If a third input argument is present, then a figure will show the discrete 31 | % L-curve in log-log scale and also indicate the found corner. 32 | 33 | % Reference: P. C. Hansen, T. K. Jensen and G. Rodriguez, "An adaptive 34 | % pruning algorithm for the discrete L-curve criterion," J. Comp. Appl. 35 | % Math., 198 (2007), 483-492. 36 | 37 | % Initialization of data 38 | rho = rho(:); % Make rho and eta column vectors. 39 | eta = eta(:); 40 | 41 | if (nargin < 3) | isempty(fig) 42 | fig = 0; % Default is no figure. 43 | elseif fig < 0, 44 | fig = 0; 45 | end 46 | 47 | info = 0; 48 | 49 | fin = isfinite(rho+eta); % NaN or Inf will cause trouble. 50 | nzr = rho.*eta~=0; % A zero will cause trouble. 51 | kept = find(fin & nzr); 52 | if isempty(kept) 53 | error('Too many Inf/NaN/zeros found in data') 54 | end 55 | if length(kept) < length(rho) 56 | info = info + 1; 57 | % warning('Corner:warnings', ... 58 | % ['Bad data - Inf, NaN or zeros found in data\n' ... 59 | % ' Continuing with the remaining data']) 60 | end 61 | rho = rho(kept); % rho and eta with bad data removed. 62 | eta = eta(kept); 63 | 64 | if any(rho(1:end-1)eta(2:end)) 65 | info = info + 10; 66 | %warning('Corner:warnings', 'Lack of monotonicity') 67 | end 68 | 69 | % Prepare for adaptive algorithm. 70 | nP = length(rho); % Number of points. 71 | P = log10([rho eta]); % Coordinates of the loglog L-curve. 72 | V = P(2:nP,:)-P(1:nP-1,:); % The vectors defined by these coordinates. 73 | v = sqrt(sum(V.^2,2)); % The length of the vectors. 74 | W = V./repmat(v,1,2); % Normalized vectors. 75 | clist = []; % List of candidates. 76 | p = min(5, nP-1); % Number of vectors in pruned L-curve. 77 | convex = 0; % Are the pruned L-curves convex? 78 | 79 | % Sort the vectors according to the length, the longest first. 80 | [Y,I] = sort(v); 81 | I = flipud(I); 82 | 83 | % Main loop -- use a series of pruned L-curves. The two functions 84 | % 'Angles' and 'Global_Behavior' are used to locate corners of the 85 | % pruned L-curves. Put all the corner candidates in the clist vector. 86 | while p < (nP-1)*2 87 | elmts = sort(I(1:min(p, nP-1))); 88 | 89 | % First corner location algorithm 90 | candidate = Angles( W(elmts,:), elmts); 91 | if candidate>0, 92 | convex = 1; 93 | end 94 | if candidate & ~any(clist==candidate) 95 | clist = [clist;candidate]; 96 | end 97 | 98 | % Second corner location algorithm 99 | candidate = Global_Behavior(P, W(elmts,:), elmts); 100 | if ~any(clist==candidate) 101 | clist = [clist; candidate]; 102 | end 103 | 104 | p = p*2; 105 | end 106 | 107 | % Issue a warning and return if none of the pruned L-curves are convex. 108 | if convex==0 109 | k_corner = []; 110 | info = info + 100; 111 | %warning('Corner:warnings', 'Lack of convexity') 112 | return 113 | end 114 | 115 | % Put rightmost L-curve point in clist if not already there; this is 116 | % used below to select the corner among the corner candidates. 117 | if sum(clist==1) == 0 118 | clist = [1;clist]; 119 | end 120 | 121 | % Sort the corner candidates in increasing order. 122 | clist = sort(clist); 123 | 124 | % Select the best corner among the corner candidates in clist. 125 | % The philosophy is: select the corner as the rightmost corner candidate 126 | % in the sorted list for which going to the next corner candidate yields 127 | % a larger increase in solution (semi)norm than decrease in residual norm, 128 | % provided that the L-curve is convex in the given point. If this is never 129 | % the case, then select the leftmost corner candidate in clist. 130 | 131 | vz = find(diff(P(clist,2)) ... % Points where the increase in solution 132 | >= abs(diff(P(clist,1)))); % (semi)norm is larger than or equal 133 | % to the decrease in residual norm. 134 | if length(vz)>1 135 | if(vz(1) == 1), vz = vz(2:end); end 136 | elseif length(vz)==1 137 | if(vz(1) == 1), vz = []; end 138 | end 139 | 140 | if isempty(vz) 141 | % No large increase in solution (semi)norm is found and the 142 | % leftmost corner candidate in clist is selected. 143 | index = clist(end); 144 | else 145 | % The corner is selected as described above. 146 | vects = [P(clist(2:end),1)-P(clist(1:end-1),1) ... 147 | P(clist(2:end),2)-P(clist(1:end-1),2)]; 148 | vects = sparse(diag(1./sqrt(sum(vects.^2,2)))) * vects; 149 | delta = vects(1:end-1,1).*vects(2:end,2) ... 150 | - vects(2:end,1).*vects(1:end-1,2); 151 | vv = find(delta(vz-1)<=0); 152 | if isempty(vv) 153 | index = clist(vz(end)); 154 | else 155 | index = clist(vz(vv(1))); 156 | end 157 | end 158 | 159 | % Corner according to original vectors without Inf, NaN, and zeros removed. 160 | k_corner = kept(index); 161 | 162 | if fig % Show log-log L-curve and indicate the found corner. 163 | figure(fig); clf 164 | diffrho2 = (max(P(:,1))-min(P(:,1)))/2; 165 | diffeta2 = (max(P(:,2))-min(P(:,2)))/2; 166 | loglog(rho, eta, 'k--o'); hold on; axis square; 167 | % Mark the corner. 168 | loglog([min(rho)/100,rho(index)],[eta(index),eta(index)],':r',... 169 | [rho(index),rho(index)],[min(eta)/100,eta(index)],':r') 170 | % Scale axes to same number of decades. 171 | if abs(diffrho2)>abs(diffeta2), 172 | ax(1) = min(P(:,1)); ax(2) = max(P(:,1)); 173 | mid = min(P(:,2)) + (max(P(:,2))-min(P(:,2)))/2; 174 | ax(3) = mid-diffrho2; ax(4) = mid+diffrho2; 175 | else 176 | ax(3) = min(P(:,2)); ax(4) = max(P(:,2)); 177 | mid = min(P(:,1)) + (max(P(:,1))-min(P(:,1)))/2; 178 | ax(1) = mid-diffeta2; ax(2) = mid+diffeta2; 179 | end 180 | ax = 10.^ax; ax(1) = ax(1)/2; axis(ax); 181 | xlabel('residual norm || A x - b ||_2') 182 | ylabel('solution (semi)norm || L x ||_2'); 183 | title(sprintf('Discrete L-curve, corner at %d', k_corner)); 184 | end 185 | 186 | % ========================================================================= 187 | % First corner finding routine -- based on angles 188 | 189 | function index = Angles( W, kv) 190 | 191 | % Wedge products 192 | delta = W(1:end-1,1).*W(2:end,2) - W(2:end,1).*W(1:end-1,2); 193 | 194 | [mm kk] = min(delta); 195 | if mm < 0 % Is it really a corner? 196 | index = kv(kk) + 1; 197 | else % If there is no corner, return 0. 198 | index = 0; 199 | end 200 | 201 | % ========================================================================= 202 | % Second corner finding routine -- based on global behavior of the L-curve 203 | 204 | function index = Global_Behavior(P, vects, elmts) 205 | 206 | hwedge = abs(vects(:,2)); % Abs of wedge products between 207 | % normalized vectors and horizontal, 208 | % i.e., angle of vectors with horizontal. 209 | [An, In] = sort(hwedge); % Sort angles in increasing order. 210 | 211 | % Locate vectors for describing horizontal and vertical part of L-curve. 212 | count = 1; 213 | ln = length(In); 214 | mn = In(1); 215 | mx = In(ln); 216 | while(mn>=mx) 217 | mx = max([mx In(ln-count)]); 218 | count = count + 1; 219 | mn = min([mn In(count)]); 220 | end 221 | if count > 1 222 | I = 0; J = 0; 223 | for i=1:count 224 | for j=ln:-1:ln-count+1 225 | if(In(i) < In(j)) 226 | I = In(i); J = In(j); break 227 | end 228 | end 229 | if I>0, break; end 230 | end 231 | else 232 | I = In(1); J = In(ln); 233 | end 234 | 235 | % Find intersection that describes the "origin". 236 | x3 = P(elmts(J)+1,1)+(P(elmts(I),2)-P(elmts(J)+1,2))/(P(elmts(J)+1,2) ... 237 | -P(elmts(J),2))*(P(elmts(J)+1,1)-P(elmts(J),1)); 238 | origin = [x3 P(elmts(I),2)]; 239 | 240 | % Find distances from the original L-curve to the "origin". The corner 241 | % is the point with the smallest Euclidian distance to the "origin". 242 | dists = (origin(1)-P(:,1)).^2+(origin(2)-P(:,2)).^2; 243 | [Y,index] = min(dists); -------------------------------------------------------------------------------- /Code/FEMIC_discrep.m: -------------------------------------------------------------------------------- 1 | function [x_delta,lambda] = discrep(U,s,V,b,delta,x_0) 2 | %DISCREP Discrepancy principle criterion for choosing the reg. parameter. 3 | % 4 | % [x_delta,lambda] = discrep(U,s,V,b,delta,x_0) 5 | % [x_delta,lambda] = discrep(U,sm,X,b,delta,x_0) , sm = [sigma,mu] 6 | % 7 | % Least squares minimization with a quadratic inequality constraint: 8 | % min || x - x_0 || subject to || A x - b || <= delta 9 | % min || L (x - x_0) || subject to || A x - b || <= delta 10 | % where x_0 is an initial guess of the solution, and delta is a 11 | % positive constant. Requires either the compact SVD of A saved as 12 | % U, s, and V, or part of the GSVD of (A,L) saved as U, sm, and X. 13 | % The regularization parameter lambda is also returned. 14 | % 15 | % If delta is a vector, then x_delta is a matrix such that 16 | % x_delta = [ x_delta(1), x_delta(2), ... ] . 17 | % 18 | % If x_0 is not specified, x_0 = 0 is used. 19 | 20 | % Reference: V. A. Morozov, "Methods for Solving Incorrectly Posed 21 | % Problems", Springer, 1984; Chapter 26. 22 | 23 | % Per Christian Hansen, IMM, August 6, 2007. 24 | 25 | % Initialization. 26 | m = size(U,1); n = size(V,1); 27 | [p,ps] = size(s); ld = length(delta); 28 | x_delta = zeros(n,ld); lambda = zeros(ld,1); rho = zeros(p,1); 29 | if (min(delta)<0) 30 | error('Illegal inequality constraint delta') 31 | end 32 | if (nargin==5), x_0 = zeros(n,1); end 33 | if (ps == 1), omega = V'*x_0; else omega = V\x_0; end 34 | 35 | % Compute residual norms corresponding to TSVD/TGSVD. 36 | beta = U'*b; 37 | if (ps == 1) 38 | delta_0 = norm(b - U*beta); 39 | rho(p) = delta_0^2; 40 | for i=p:-1:2 41 | rho(i-1) = rho(i) + (beta(i) - s(i)*omega(i))^2; 42 | end 43 | else 44 | delta_0 = norm(b - U*beta); 45 | rho(1) = delta_0^2; 46 | for i=1:p-1 47 | rho(i+1) = rho(i) + (beta(i) - s(i,1)*omega(i))^2; 48 | end 49 | end 50 | 51 | % Check input. 52 | if (min(delta) < delta_0) 53 | error('Irrelevant delta < || (I - U*U'')*b ||') 54 | end 55 | 56 | % Determine the initial guess via rho-vector, then solve the nonlinear 57 | % equation || b - A x ||^2 - delta_0^2 = 0 via Newton's method. 58 | if (ps == 1) 59 | 60 | % The standard-form case. 61 | s2 = s.^2; 62 | for k=1:ld 63 | if (delta(k)^2 >= norm(beta - s.*omega)^2 + delta_0^2) 64 | x_delta(:,k) = x_0; 65 | else 66 | [dummy,kmin] = min(abs(rho - delta(k)^2)); 67 | lambda_0 = s(kmin); 68 | lambda(k) = newton(lambda_0,delta(k),s,beta,omega,delta_0); 69 | e = s./(s2 + lambda(k)^2); f = s.*e; 70 | x_delta(:,k) = V(:,1:p)*(e.*beta + (1-f).*omega); 71 | end 72 | end 73 | 74 | elseif (m>=n) 75 | 76 | % The overdetermined or square genera-form case. 77 | omega = omega(1:p); gamma = s(:,1)./s(:,2); 78 | x_u = V(:,p+1:n)*beta(p+1:n); 79 | for k=1:ld 80 | if (delta(k)^2 >= norm(beta(1:p) - s(:,1).*omega)^2 + delta_0^2) 81 | x_delta(:,k) = V*[omega;U(:,p+1:n)'*b]; 82 | else 83 | [dummy,kmin] = min(abs(rho - delta(k)^2)); 84 | lambda_0 = gamma(kmin); 85 | lambda(k) = newton(lambda_0,delta(k),s,beta(1:p),omega,delta_0); 86 | e = gamma./(gamma.^2 + lambda(k)^2); f = gamma.*e; 87 | x_delta(:,k) = V(:,1:p)*(e.*beta(1:p)./s(:,2) + ... 88 | (1-f).*s(:,2).*omega) + x_u; 89 | end 90 | end 91 | 92 | else 93 | 94 | % The underdetermined general-form case. 95 | omega = omega(1:p); gamma = s(:,1)./s(:,2); 96 | x_u = V(:,p+1:m)*beta(p+1:m); 97 | for k=1:ld 98 | if (delta(k)^2 >= norm(beta(1:p) - s(:,1).*omega)^2 + delta_0^2) 99 | x_delta(:,k) = V*[omega;U(:,p+1:m)'*b]; 100 | else 101 | [dummy,kmin] = min(abs(rho - delta(k)^2)); 102 | lambda_0 = gamma(kmin); 103 | lambda(k) = newton(lambda_0,delta(k),s,beta(1:p),omega,delta_0); 104 | e = gamma./(gamma.^2 + lambda(k)^2); f = gamma.*e; 105 | x_delta(:,k) = V(:,1:p)*(e.*beta(1:p)./s(:,2) + ... 106 | (1-f).*s(:,2).*omega) + x_u; 107 | end 108 | end 109 | end 110 | 111 | %------------------------------------------------------------------- 112 | 113 | function lambda = newton(lambda_0,delta,s,beta,omega,delta_0) 114 | %NEWTON Newton iteration (utility routine for DISCREP). 115 | % 116 | % lambda = newton(lambda_0,delta,s,beta,omega,delta_0) 117 | % 118 | % Uses Newton iteration to find the solution lambda to the equation 119 | % || A x_lambda - b || = delta , 120 | % where x_lambda is the solution defined by Tikhonov regularization. 121 | % 122 | % The initial guess is lambda_0. 123 | % 124 | % The norm || A x_lambda - b || is computed via s, beta, omega and 125 | % delta_0. Here, s holds either the singular values of A, if L = I, 126 | % or the c,s-pairs of the GSVD of (A,L), if L ~= I. Moreover, 127 | % beta = U'*b and omega is either V'*x_0 or the first p elements of 128 | % inv(X)*x_0. Finally, delta_0 is the incompatibility measure. 129 | 130 | % Reference: V. A. Morozov, "Methods for Solving Incorrectly Posed 131 | % Problems", Springer, 1984; Chapter 26. 132 | 133 | % Per Christian Hansen, IMM, 12/29/97. 134 | 135 | % Set defaults. 136 | thr = sqrt(eps); % Relative stopping criterion. 137 | it_max = 50; % Max number of iterations. 138 | 139 | % Initialization. 140 | if (lambda_0 < 0) 141 | error('Initial guess lambda_0 must be nonnegative') 142 | end 143 | [p,ps] = size(s); 144 | if (ps==2), sigma = s(:,1); s = s(:,1)./s(:,2); end 145 | s2 = s.^2; 146 | 147 | % Use Newton's method to solve || b - A x ||^2 - delta^2 = 0. 148 | % It was found experimentally, that this formulation is superior 149 | % to the formulation || b - A x ||^(-2) - delta^(-2) = 0. 150 | lambda = lambda_0; step = 1; it = 0; 151 | while (abs(step) > thr*lambda & abs(step) > thr & it < it_max), it = it+1; 152 | f = s2./(s2 + lambda^2); 153 | if (ps==1) 154 | r = (1-f).*(beta - s.*omega); 155 | z = f.*r; 156 | else 157 | r = (1-f).*(beta - sigma.*omega); 158 | z = f.*r; 159 | end 160 | step = (lambda/4)*(r'*r + (delta_0+delta)*(delta_0-delta))/(z'*r); 161 | lambda = lambda - step; 162 | % If lambda < 0 then restart with smaller initial guess. 163 | if (lambda < 0), lambda = 0.5*lambda_0; lambda_0 = 0.5*lambda_0; end 164 | end 165 | 166 | % Terminate with an error if too many iterations. 167 | if (abs(step) > thr*lambda & abs(step) > thr) 168 | error(['Max. number of iterations (',num2str(it_max),') reached']) 169 | end -------------------------------------------------------------------------------- /Code/FEMIC_forward2D.m: -------------------------------------------------------------------------------- 1 | % function [out]=FEMIC_forward2D(params,d,f,r,q,mdltype) 2 | % 3 | % This MATLAB code calls the FEMIC forward modeling routines to compute 4 | % observed conuctivity values for FDEM instruments. 5 | % 6 | % G. Schultz 2008 7 | %% 8 | % INPUTS: 9 | % params = model parameters to be optimizaed 10 | % d = depths (initial) (1 x mlayers) 11 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 12 | % sigma = standard deviations on measurements (1 x 2*length(f)) 13 | % f = frequencies 14 | % r = separation distances between Rx and Tx for bistatic case 15 | % q = [=1,2,3] to designate the data types represented in the pobs input 16 | % array: 1=Vertical Magnetic Dipole only 17 | % 2=Horizontal Magnetic Dipole only 18 | % 3=Both VMD and HMD data 19 | %% 20 | % OUTPUTS: 21 | % p_final = the final model array in [P stations x N frequencies (2xN for 22 | % 23 | % EXAMPLE USAGE: 24 | % [g]=FEMIC_forward2D(params,d,f,r,q,mdltype); 25 | 26 | function [out]=FEMIC_forward2D(params,d,vall) 27 | 28 | %% Initialize array size and constant parameters 29 | szp=size(params); % number of stations 30 | P=szp(2); 31 | %M=length(d); 32 | M = szp(1); % number of model parameters 33 | Md = length(d); % number of layer thicknesses 34 | Ms = M-Md; % should be the number of conducitivities 35 | %N=szp(1); 36 | load SS 37 | N=length(S.freq); % number of frequencies 38 | %if q==3, 39 | % NN=2*N; % twice the frequenices if both VDM and HDM used 40 | %else % number of data (freq x 2) 41 | % NN=N; % total number of data points (same as N if only one orientation of data is used) 42 | %end 43 | %NP=NN*P; % size of the data set 44 | %MP=M*P; % size of the model output set 45 | %dlmwrite('q.txt',q); 46 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 47 | %% Initialize the regularization matrices 48 | po=params(1:M,:); 49 | % Create a NPxNP diagonal weighting matrix whose elements are the inverse of the 50 | % estimated (or measured) stanard deviations of the measurements 51 | dp=1; 52 | tic; 53 | isOpen = matlabpool('size') > 0;%plotdoi=0; 54 | if isOpen==0 55 | matlabpool('local',vall) 56 | end 57 | %dlmwrite('d.dat',d); 58 | M.k = length(d); % number of layers 59 | M.thk = d'; % layer thicknesses (m), enter zero for half-space layer 60 | %M.con = [.01;.001;.1]; % layer conductivities (S/m) 61 | M.chie = zeros(length(S.freq),1); % layer dielectric susceptibilities (SI) eps = eps_0 * (1 + chie) 62 | M.chim = zeros(length(S.freq),1); % layer magnetic susceptibilities (SI) mu = mu_0 * (1 + chim) 63 | el = -1; 64 | %% Outer loop over maximum number of iterations (breaks if alternate 65 | %% convergence criteria are met 66 | warning off 67 | for ii=1:P, % loop over all measurement positions (B1) 68 | % fprintf(' Calibration and filtering the raw data are in progress.. %3.0f\n') 69 | pin=[po(:,ii)]; %da=d(:,ii); % model input parameters for this position (ii) 70 | M.con=(1./pin); 71 | [Gout] = fdem1dfwd(S,M,el,0); 72 | %[GG(:,ii),JJ]=jacnmodelMdl_mat(f,r,pin,d); 73 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 74 | % Compute the model kernel Gout, and Jacobian matrix J 75 | % [Gout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,2); 76 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 77 | %[t,x,y] = sim('jacobianMdl3'); 78 | mdl(:,ii) = Gout; % place current Gout vector in the global GG array 79 | end % end (B1) loop over measurement positions 80 | 81 | elap_time=toc/60; 82 | mdlIdx = mdl(:,1)>0; 83 | j=0; 84 | for i=1:length(mdlIdx), 85 | if mdlIdx(i)~=0, 86 | j=j+1; 87 | out(j,:)=mdl(i,:); 88 | end 89 | end 90 | % fo=length(out); 91 | %if q==2 92 | % out(length(f)+1:fo)=0; 93 | %end -------------------------------------------------------------------------------- /Code/FEMIC_gcorner.m: -------------------------------------------------------------------------------- 1 | function [k_corner,cornerval,nx,ny] = FEMIC_gcorner(xx,yy) 2 | %keyboard; 3 | x = log10(xx); 4 | y = log10(yy); 5 | minX = min(x);%(min(x)-(max(x)-min(x))/5); 6 | maxX = max(x);%(max(x)+(max(x)-min(x))/5); 7 | dx = (max(x)-min(x))/255; 8 | xp = [minX:dx:maxX]'; 9 | yp = spline(x,y,xp); 10 | grr = -2.*ones(length(xp),1); 11 | for i=21:length(xp), 12 | grr(i) = sum( diff( yp(i-20:i),2 ) ); 13 | end 14 | % while icc<=21, 15 | % [mxc,icc] = max(grr(ix:end)); 16 | % ix=icc; 17 | % return 18 | % end 19 | %keyboard 20 | [mxc,icc] = max(grr); 21 | k_corner = icc; 22 | cornerval = 10.^xp(k_corner); 23 | nx = 10.^xp; 24 | ny = 10.^yp; 25 | -------------------------------------------------------------------------------- /Code/FEMIC_inverse5.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/FEMIC_inverse5.fig -------------------------------------------------------------------------------- /Code/FEMIC_maxentropy.m: -------------------------------------------------------------------------------- 1 | function [x_lambda,rho,eta,data,X] = FEMIC_maxentropy(A,b,lambda,w,x0) 2 | % 3 | % Maximum entropy regularization. 4 | % EXAMPLE USAGE: 5 | % [x_lambda,rho,eta] = maxent(A,b,lambda,w,x0) 6 | % 7 | % 8 | % Modified maxent.m codes originated by 9 | % Hansen and Elfving, 1992 10 | % 11 | % Maximum entropy regularization: 12 | % min { || A x - b ||^2 + lambda^2*x'*log(diag(w)*x) } , 13 | % where -x'*log(diag(w)*x) is the entropy of the solution x. 14 | % If no weights w are specified, unit weights are used. 15 | % 16 | % If lambda is a vector, then x_lambda is a matrix such that 17 | % x_lambda = [x_lambda(1), x_lambda(2), ... ] . 18 | % 19 | % This routine uses a nonlinear conjugate gradient algorithm with "soft" 20 | % line search and a step-length control that insures a positive solution. 21 | % If the starting vector x0 is not specified, then the default is 22 | % x0 = norm(b)/norm(A,1)*ones(n,1) . 23 | % 24 | % 25 | % Reference: R. Fletcher, "Practical Methods for Optimization", 26 | % Second Edition, Wiley, Chichester, 1987. 27 | 28 | % Set defaults. 29 | flat = 1e-3; % Measures a flat minimum. 30 | flatrange = 10; % How many iterations before a minimum is considered flat. 31 | maxit = 150; % Maximum number of CG iterations. 32 | minstep = 1e-12; % Determines the accuracy of x_lambda. 33 | sigma = 0.5; % Threshold used in descent test. 34 | tau0 = 1e-3; % Initial threshold used in secant root finder. 35 | 36 | % Initialization. 37 | [m,n] = size(A); x_lambda = zeros(n,length(lambda)); F = zeros(maxit,1); 38 | if (min(lambda) <= 0) 39 | error('Regularization parameter lambda must be positive') 40 | end 41 | if (nargin ==3), w = ones(n,1); end 42 | if (nargin < 5), x0 = ones(n,1); end 43 | 44 | % Treat each lambda separately. 45 | for j=1:length(lambda); 46 | 47 | % Prepare for nonlinear CG iteration. 48 | l2 = lambda(j)^2; 49 | x = x0; Ax = A*x; 50 | g = 2*A'*(Ax - b) + l2*(1 + log(w.*x)); 51 | p = -g; 52 | r = Ax - b; 53 | 54 | % Start the nonlinear CG iteration here. 55 | delta_x = x; dF = 1; it = 0; phi0 = p'*g; 56 | while (norm(delta_x) > minstep*norm(x) & dF > flat & it < maxit & phi0 < 0) 57 | it = it + 1; 58 | 59 | % Compute some CG quantities. 60 | Ap = A*p; gamma = Ap'*Ap; v = A'*Ap; 61 | 62 | % Determine the steplength alpha by "soft" line search in which 63 | % the minimum of phi(alpha) = p'*g(x + alpha*p) is determined to 64 | % a certain "soft" tolerance. 65 | % First compute initial parameters for the root finder. 66 | alpha_left = 0; phi_left = phi0; 67 | if (min(p) >= 0) 68 | alpha_right = -phi0/(2*gamma); 69 | h = 1 + alpha_right*p./x; 70 | else 71 | % Step-length control to insure a positive x + alpha*p. 72 | I = find(p < 0); 73 | alpha_right = min(-x(I)./p(I)); 74 | h = 1 + alpha_right*p./x; delta = eps; 75 | while (min(h) <= 0) 76 | alpha_right = alpha_right*(1 - delta); 77 | h = 1 + alpha_right*p./x; 78 | delta = delta*2; 79 | end 80 | end 81 | z = log(h); 82 | phi_right = phi0 + 2*alpha_right*gamma + l2*p'*z; 83 | alpha = alpha_right; phi = phi_right; 84 | 85 | if (phi_right <= 0) 86 | 87 | % Special treatment of the case when phi(alpha_right) = 0. 88 | z = log(1 + alpha*p./x); 89 | g_new = g + l2*z + 2*alpha*v; t = g_new'*g_new; 90 | beta = (t - g'*g_new)/(phi - phi0); 91 | 92 | else 93 | 94 | % The regular case: improve the steplength alpha iteratively 95 | % until the new step is a descent step. 96 | t = 1; u = 1; tau = tau0; 97 | while (u > -sigma*t) 98 | 99 | % Use the secant method to improve the root of phi(alpha) = 0 100 | % to within an accuracy determined by tau. 101 | while (abs(phi/phi0) > tau) 102 | alpha = (alpha_left*phi_right - alpha_right*phi_left)/... 103 | (phi_right - phi_left); 104 | z = log(1 + alpha*p./x); 105 | phi = phi0 + 2*alpha*gamma + l2*p'*z; 106 | if (phi > 0) 107 | alpha_right = alpha; phi_right = phi; 108 | else 109 | alpha_left = alpha; phi_left = phi; 110 | end 111 | end 112 | 113 | % To check the descent step, compute u = p'*g_new and 114 | % t = norm(g_new)^2, where g_new is the gradient at x + alpha*p. 115 | g_new = g + l2*z + 2*alpha*v; t = g_new'*g_new; 116 | beta = (t - g'*g_new)/(phi - phi0); 117 | u = -t + beta*phi; 118 | tau = tau/10; 119 | 120 | end % End of improvement iteration. 121 | 122 | end % End of regular case. 123 | 124 | % Update the iteration vectors. 125 | g = g_new; delta_x = alpha*p; 126 | x = x + delta_x; 127 | p = -g + beta*p; 128 | r = r + alpha*Ap; 129 | phi0 = p'*g; 130 | 131 | % Compute some norms and check for flat minimum. 132 | rho(j,1) = norm(r); eta(j,1) = x'*log(w.*x); 133 | F(it) = rho(j,1)^2 + l2*eta(j,1); 134 | if (it <= flatrange) 135 | dF = 1; 136 | else 137 | dF = abs(F(it) - F(it-flatrange))/abs(F(it)); 138 | end 139 | 140 | data(it,:) = [F(it),norm(delta_x),norm(g)]; 141 | X(:,it) = x; 142 | 143 | end % End of iteration for x_lambda(j). 144 | 145 | x_lambda(:,j) = x; 146 | 147 | end -------------------------------------------------------------------------------- /Code/FEMIC_plotINVinterim.m: -------------------------------------------------------------------------------- 1 | %% Function to support FEMIC inversion parameter display 2 | % this function may be called on each iteration of the model to display the 3 | % model error, model vs. observation comparison, and model parameters 4 | % profile at a selected station location. 5 | % 6 | % G. Schultz 2008 7 | 8 | function [hplot] = FEMIC_plotINVinterim(gmodel,obs,f,iter,max_iter,p,mdlD,err,p0,pmin,pmax) 9 | 10 | %% Postion the figure window in the screen 11 | p0=1./10.^p0;p=1./10.^p; 12 | Screen.size = get(0, 'ScreenSize'); %Determines the Size of the Screen 13 | %Position %Set for a screen of 1024x768 and to set above windows taskbar 14 | Screen.Left = Screen.size(1); 15 | Screen.Bottom = Screen.size(2); 16 | Screen.Width = Screen.size(3); 17 | Screen.Height = Screen.size(4); 18 | 19 | hplot=figure(12); 20 | 21 | set(gcf,'NumberTitle','off',... 22 | 'Name','FEMIC Frequency-domain EMI Inversion',... 23 | 'Resize','on'); 24 | %% Plots the forward model values and observations at each iteration 25 | hold on 26 | set(gcf,'Position',[floor((Screen.Width-610)/1.5) floor((Screen.Height-610)/2) 600 600]); 27 | subplot(211); 28 | plot(f,obs,'k*',f,gmodel,'rd-','MarkerSize',6+1.5*iter); 29 | df = (max(f)-min(f))/10; 30 | set(gca,'XLim',[min(f)-df max(f)+df]); 31 | set(gca,'YLim',[min([gmodel;obs])-0.2*min([gmodel;obs]) max([gmodel;obs])+0.2*max([gmodel;obs])]); 32 | xlabel('Frequency (Hz)');ylabel('Quadrature'); legend('Observed','Predicted'); 33 | title(['Iteration ',num2str(iter),' - RMSerr= ',num2str(err)]); 34 | set(gca,'FontSize',12) 35 | %% Plots the RMS residual errors between model and observations 36 | hold on 37 | subplot(223); 38 | plot(iter,log10(err),'*') 39 | set(gca,'XLim',[0 max_iter]); 40 | set(gca,'YLim',[-2 2]); 41 | xlabel('Iteration'); ylabel('log_1_0(RMS Error)'); 42 | set(gca,'FontSize',12) 43 | 44 | %% Sorts the model parameters vector for plotting 45 | D=[mdlD]; 46 | D(end) = D(end-1); 47 | d(1,:) = [0 1]; 48 | eca(1,:) = [p(1) p(1)]; 49 | ip(1,:) =[p0(1) p0(1)]; 50 | for i=2:length(D), 51 | d(i,:) = [d(i-1,2) d(i-1,2)+D(i)]; 52 | eca(i,:)=[p(i) p(i)]; 53 | ip(i,:) = [p0(i) p0(i)]; 54 | end 55 | dd = reshape(d',2*length(d),1); 56 | eeca = reshape(eca',2*length(d),1); 57 | oeca = reshape(ip',2*length(d),1); 58 | 59 | %% Plots the current model 60 | hold on; 61 | subplot(224); 62 | plot(oeca,-dd,'r.-','LineWidth',2); 63 | hold on 64 | plot(eeca,-dd,'k-','LineWidth',iter); 65 | hold on 66 | plot([pmin;pmin],[0;min(-dd)],'g-',[pmax;pmax],[0;min(-dd)],'g-',... 67 | 'LineWidth',2); 68 | set(gca,'YLim',[min(-dd) 0]); 69 | set(gca,'XLim',[-2 1100]); 70 | xlabel('Resist. (Ohm m)'); ylabel('Depth (m)'); 71 | set(gca,'FontSize',12) 72 | shg -------------------------------------------------------------------------------- /Code/FEMIC_svd.m: -------------------------------------------------------------------------------- 1 | function [U,s,V] = csvd(A,tst) 2 | %CSVD Compact singular value decomposition. 3 | % 4 | % s = csvd(A) 5 | % [U,s,V] = csvd(A) 6 | % [U,s,V] = csvd(A,'full') 7 | % 8 | % Computes the compact form of the SVD of A: 9 | % A = U*diag(s)*V', 10 | % where 11 | % U is m-by-min(m,n) 12 | % s is min(m,n)-by-1 13 | % V is n-by-min(m,n). 14 | % 15 | % If a second argument is present, the full U and V are returned. 16 | 17 | 18 | if (nargin==1) 19 | if (nargout > 1) 20 | [m,n] = size(A); 21 | if (m >= n) 22 | [U,s,V] = svd(full(A),0); s = diag(s); 23 | else 24 | [V,s,U] = svd(full(A)',0); s = diag(s); 25 | end 26 | else 27 | U = svd(full(A)); 28 | end 29 | else 30 | if (nargout > 1) 31 | [U,s,V] = svd(full(A)); s = diag(s); 32 | else 33 | U = svd(full(A)); 34 | end 35 | end -------------------------------------------------------------------------------- /Code/FEMIC_tost.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error, G]=FEMIC_tost(params,d,pobs,sigma,f,r,muv,... 53 | err_tol,max_iter,q) 54 | 55 | %% Initialize array size and constant parameters 56 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 57 | szp=size(pobs); % number of frequencies (x2) by number of stations 58 | P=szp(2); % number of data (freq x 2) 59 | %M=length(d); 60 | M = length(params); % number of model parameters 61 | Md = length(d); % number of layer thicknesses 62 | Ms = M-Md; % should be the number of conducitivities 63 | %N=szp(1); 64 | N=length(f); % number of frequencies 65 | if q==3, 66 | NN=2*N; % twice the frequenices if both VDM and HDM used 67 | else 68 | NN=N; % total number of data points (same as N if only one orientation of data is used) 69 | end 70 | NP=NN*P; % size of the data set 71 | MP=M*P; 72 | % size of the model output set 73 | xc=params; 74 | params=repmat(params,1,P); 75 | 76 | obs=pobs(:);%reshape(pobs,NP,1); 77 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 78 | sigma=repmat(sigma, P, 1); 79 | W=diag(1./sigma);MTX.W=W; 80 | dp=1; 81 | tic; 82 | mref=xc; 83 | itc = 0; 84 | misfit = []; gc = 1; normg0 = 1; 85 | while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 86 | % iteration count 87 | itc = itc+1; 88 | for ii=1:P, % loop over all measurement positions (B1) 89 | fprintf(' Computing profile %3.0f\n',ii) 90 | pin=xc; % model input parameters for this position (ii) 91 | [Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 92 | GG(:,ii) = Gout(1:NN); % place current Gout vector in the global GG array 93 | JJ = Jout(1:NN,1:M); % organize the global Jacobian matrix 94 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 95 | end % end (B1) loop over measurement positions 96 | G=reshape(GG,NP,1); 97 | elap_time=toc/60; 98 | fd = 0.5*(G-obs)'*(W)*(G-obs); 99 | if itc == 1 & isempty(muv); 100 | para.BETA = 0; 101 | end; 102 | wta=ones(Md,P); 103 | dx=1;dz=d;%ones(length(d),1); 104 | nx=length(dx);nz=length(dz); 105 | [Gx Gz]=grad(dx,dz);sx=1;sz=1;als=1e-5; 106 | Gs = [sx*Gx;sz*Gz]; 107 | Wt = spdiags(wta(:),0,nx*nz,nx*nz); 108 | MW = Wt' * ( Gs' * Gs ) * Wt;pin=reshape(pin,length(pin),1);mref=reshape(mref,length(mref),1); 109 | fm = 0.5*muv*((pin-mref)'*MW*(pin-mref)); 110 | fc =fd+fm; 111 | grad_fm = muv*MW*(pin-mref);dlmwrite('gm.dat',grad_fm); 112 | grad_fd = J'*(G-obs);dlmwrite('gf.dat',grad_fd); 113 | % Combine the gradients 114 | gc = grad_fd + grad_fm; 115 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 116 | rms_error = misfit; 117 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 118 | MTX.mc = xc; 119 | para.intol = 2e-4; % tol for inexact newton solver (ipcg) 120 | para.inintol = 1e-9; % tol for the forward and adjoint problems 121 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 122 | para.init = 3; % number of ipcg iterations 123 | para.ilutol = 0; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 124 | para.alp=1e-4; % Parameter for line search 125 | MTX.WTW=MW;dlmwrite('J.dat',J); 126 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J); 127 | if max(abs(s)) < 1e-3, 128 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 129 | fprintf('STEP size too small CONVERGE '); return; 130 | end; 131 | 132 | mu_LS = 1; 133 | iarm = 0; 134 | while 1, 135 | xt = pin + mu_LS*s; 136 | for ii=1:P,%% Loop over all station positions (B2) 137 | pin=[xt(:,ii)]; 138 | [Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 139 | G_trial(:,ii) = Gout(1:NN); 140 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 141 | end % end (B2) loop over station positions 142 | G_try=G_trial(:);%reshape(G_trial,NP,1); 143 | 144 | fd = 0.5*(G_try-obs)'*W*(G_trial-obs); 145 | 146 | %automatically determine a beta guess 147 | if itc == 1 & muv ==0; 148 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 149 | end; 150 | fm = 0.5*muv*( (xt-mref)'*muv*(xt-mref)); 151 | ft = fd+fm; 152 | fgoal = fc - para.alp*mu_LS*(s'*gc); 153 | 154 | if ft < fgoal, 155 | break, 156 | else 157 | break, 158 | end; 159 | 160 | fgoal = fc - para.alp*mu_LS*(s'*gc); 161 | end % end line search 162 | 163 | xc = xt; 164 | misfitnew = misfit; 165 | misfitold = misfitnew; 166 | 167 | 168 | end % end loop (A1) over iterations 169 | p_final=xt; 170 | muh_final=muv; 171 | 172 | -------------------------------------------------------------------------------- /Code/FEMIC_tost1.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error2, G]=FEMIC_tost1(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sz,wta) 53 | 54 | %% Initialize array size and constant parameters 55 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 56 | szp=size(pobs); % number of frequencies (x2) by number of stations 57 | P=szp(2); % number of data (freq x 2) 58 | params=MM.con; 59 | d=MM.thk; 60 | f=S.freq; 61 | r=S.r; 62 | M = length(d);%size(params,1); % number of model parameters 63 | Md = length(d); % number of layer thicknesses 64 | Ms = M-Md; % should be the number of conducitivities 65 | N=length(f); % number of frequencies 66 | if q==3, 67 | NN=2*N; % twice the frequenices if both VDM and HDM used 68 | else 69 | NN=N; % total number of data points (same as N if only one orientation of data is used) 70 | end 71 | NP=NN*P; % size of the data set 72 | MP=M*P; 73 | % size of the model output set 74 | xc=params; 75 | params=repmat(params,1,P); 76 | 77 | obs=pobs(:);%reshape(pobs,NP,1); 78 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 79 | %% Initialize the regularization matrices 80 | W=diag(1./sigma(:));MTX.W=W; 81 | dp=1; 82 | tic; 83 | mref=xc; 84 | %% Outer loop over maximum number of iterations (breaks if alternate 85 | %% convergence criteria are met 86 | itc = 0; 87 | misfit = []; gc = 1; normg0 = 1; 88 | while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 89 | % iteration count 90 | itc = itc+1; 91 | for ii=1:P, % loop over all measurement positions (B1) 92 | fprintf(' Computing profile %3.0f\n',ii) 93 | pin(:,ii)=xc(:,ii); % model input parameters for this position (ii) 94 | %[GG(:,ii),JJ]=jacnmodelMdl_mat(f,r,pin,d); 95 | MM.con=pin(:,ii); 96 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97 | % Compute the model kernel Gout, and Jacobian matrix J 98 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 99 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 100 | dlmwrite('Jout.dat',Jout); 101 | %[t,x,y] = sim('jacobianMdl3'); 102 | 103 | GG(:,ii) = Gout;%(1:NN); % place current Gout vector in the global GG array 104 | JJ = Jout;%(1:NN,1:6); % organize the global Jacobian matrix 105 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 106 | end % end (B1) loop over measurement positions 107 | % Reshape G into a vector 108 | G=GG(:);%reshape(GG,NP,1); 109 | elap_time=toc/60; 110 | fd = 0.5*(G-obs)'*(W)*(G-obs); 111 | if itc == 1 & isempty(muv); 112 | %%Temporarily assign a value, to be corrected later 113 | para.BETA = 0; 114 | end; 115 | dx=1*ones(P,1);dz=ones(length(d),1); 116 | nx=length(dx);nz=length(dz);V = spdiags((wta(:)), 0, nx*nz, nx*nz); 117 | dlmwrite('wta.dat',wta);dlmwrite('dx.dat',dx);dlmwrite('dz.dat',dz); 118 | [Gx, Gz]=grad(dx,dz);sx=1;als=7;%V=0; 119 | Gs = [sx*Gx;sz*Gz]; 120 | Wt = spdiags(wta(:),0,nx*nz,nx*nz); 121 | MW = Wt' * ( Gs' * Gs + als * V ) * Wt;pin=pin(:);%reshape(pin,length(pin),1); 122 | mref=mref(:);%reshape(mref,length(mref),1); 123 | fm = muv*((xc(:)-mref)'*MW*(xc(:)-mref)); 124 | %%Add them for the total Objective function 125 | fc =fd+fm; 126 | grad_fm = muv*MW*(xc-mref); 127 | grad_fd = J'*(G-obs);dlmwrite('gf.dat',grad_fd); 128 | % Combine the gradients 129 | gc = grad_fd + grad_fm; 130 | %%%% Store some quantities for later use 131 | 132 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 133 | rms_error = misfit; 134 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 135 | MTX.mc = xc; 136 | para.intol = 0; % tol for inexact newton solver (ipcg) 137 | para.inintol = 1e-9; % tol for the forward and adjoint problems 138 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 139 | para.init = 4; % number of ipcg iterations 140 | para.ilutol = 0; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 141 | para.alp=1e-4; % Parameter for line search 142 | MTX.WTW=MW;dlmwrite('J.dat',J); 143 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J,W); 144 | 145 | if max(abs(s)) < 1e-3, 146 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 147 | fprintf('STEP size too small CONVERGE '); % return; 148 | end; 149 | pin=pin(:); 150 | % Try the step 151 | mu_LS = 1; 152 | iarm = 0; 153 | while 1, 154 | 155 | 156 | xt = xc(:) + mu_LS*s; 157 | 158 | xt=reshape(xt,length(d),length(xt)/length(d));xt=xt; 159 | %pin=reshape(pin,length(d),length(xt)/length(d)); 160 | for ii=1:P,%% Loop over all station positions (B2) 161 | %pin=reshape(pin,6,10); 162 | dlmwrite('pin.dat',pin);dlmwrite('xt.dat',xt); 163 | pin=[xt(:,ii)]; 164 | MM.con=xt(:,ii); dlmwrite('ccon.dat',xt(:,ii)); 165 | %[G_trial(:,ii),J_trial]=jacnmodelMdl_mat(f,r,pin,d); 166 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167 | % Compute the model kernel Gout, and Jacobian matrix J 168 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 169 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 170 | 171 | G_trial(:,ii) = Gout(1:NN); 172 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 173 | end % end (B2) loop over station positions 174 | G_try=G_trial(:);%reshape(G_trial,NP,1); 175 | 176 | 177 | fd = 0.5*(G_try-obs)'*W*(G_try-obs); 178 | 179 | %automatically determine a beta guess 180 | if itc == 1 & muv ==0; 181 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 182 | end; 183 | fm = 0.5*muv*( (xt(:)-mref)'*muv*(xt(:)-mref)); 184 | ft = fd+fm; 185 | fgoal = fc - para.alp*mu_LS*(s'*gc); 186 | 187 | if ft < fgoal, 188 | break, 189 | else 190 | % break, 191 | iarm = iarm+1; 192 | mu_LS = mu_LS/2; 193 | end; 194 | 195 | if(iarm > 5) 196 | % disp(' Line search FAIL EXIT(0)'); 197 | % return; 198 | break, 199 | end 200 | fgoal = fc - para.alp*mu_LS*(s'*gc); 201 | end % end line search 202 | % Update model 203 | 204 | % L-Curve 205 | 206 | 207 | xc = xt; 208 | misfitnew = misfit; 209 | misfitold = misfitnew; 210 | rms_error2(:,itc)=rms_error; 211 | 212 | 213 | end % end loop (A1) over iterations 214 | p_final=xt; 215 | muh_final=muv; 216 | 217 | -------------------------------------------------------------------------------- /Code/FEMIC_tost2.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error2, G,sense,cell_sensy]=FEMIC_tost2(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords,sens,cell_sens) 53 | 54 | %% Initialize array size and constant parameters 55 | MM.con(MM.con>0)=log10(MM.con(MM.con>0));%dlmwrite('init.dat',MM.con); 56 | pree=MM.con; 57 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 58 | szp=size(pobs); % number of frequencies (x2) by number of stations 59 | P=szp(2); % number of data (freq x 2) 60 | %MM.con=-2*ones(length(MM.thk),szp(2)); 61 | %M=length(d); 62 | params=MM.con; 63 | d=MM.thk; 64 | f=S.freq; 65 | r=S.r; 66 | M = length(d);%size(params,1); % number of model parameters 67 | Md = length(d); % number of layer thicknesses 68 | Ms = M-Md; % should be the number of conducitivities 69 | %N=szp(1); 70 | N=length(f); % number of frequencies 71 | if q==3, 72 | NN=2*N; % twice the frequenices if both VDM and HDM used 73 | else 74 | NN=N; % total number of data points (same as N if only one orientation of data is used) 75 | end 76 | NP=NN*P; % size of the data set 77 | MP=M*P; 78 | % size of the model output set 79 | xc=params; 80 | params=repmat(params,1,P);[vr, wr]=size(pobs); 81 | q=2*ones(szp(1),szp(2));%q=reshape(q,vr,wr);% 82 | obs=pobs(:);%reshape(pobs,NP,1); 83 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 84 | %% Initialize the regularization matrices 85 | % create a single vector out of the input arrays 86 | %sigma=repmat(sigma, P, 1); 87 | %po=params(1:M,:); 88 | % Create a NPxNP diagonal weighting matrix whose elements are the inverse of the 89 | % estimated (or measured) stanard deviations of the measurements 90 | W=diag(1./sigma(:));MTX.W=W; 91 | dp=1; 92 | tic; 93 | mref=xc;%muv=muv/100000; 94 | %% Outer loop over maximum number of iterations (breaks if alternate 95 | %% convergence criteria are met 96 | itc = 0; 97 | misfit = []; gc = 1; normg0 = 1; 98 | bet=linspace(100,1,max_iter); 99 | for ioo=1:max_iter%while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 100 | % iteration count 101 | itc = itc+1; 102 | for ii=1:P, % loop over all measurement positions (B1) 103 | fprintf(' Computing profile %3.0f\n',ii) 104 | pin(:,ii)=xc(:,ii); % model input parameters for this position (ii) 105 | %[GG(:,ii),JJ]=jacnmodelMdl_mat(f,r,pin,d); 106 | MM.con=pin(:,ii); 107 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 108 | if unique(q(:,ii))<2 109 | for i=1:length(f);S.tor{i}='z';end;S.tor=reshape(S.tor,length(f),1); 110 | S.tmom=-1*ones(length(f),1);S.ror=S.tor;S.rmom=S.tmom; 111 | elseif length(unique(q(:,ii)))>1 112 | disp('There is something wrong with coil configuration: review column 7 of input data for consistency'); 113 | return; 114 | end 115 | % Compute the model kernel Gout, and Jacobian matrix J 116 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 117 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118 | %[t,x,y] = sim('jacobianMdl3'); 119 | 120 | GG(:,ii) = Gout;%(1:NN); % place current Gout vector in the global GG array 121 | JJ = Jout;%(1:NN,1:6); % organize the global Jacobian matrix 122 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 123 | end % end (B1) loop over measurement positions 124 | % Reshape G into a vector 125 | G=GG(:);%reshape(GG,NP,1); 126 | elap_time=toc/60; 127 | fd =(G-obs)'*(W'*W)*(G-obs); 128 | if itc == 1 & isempty(muv); 129 | %%Temporarily assign a value, to be corrected later 130 | para.BETA = 0; 131 | end; 132 | dx=ones(P,1);wq=1:P;for i=1:length(wq); xx(:,i)=wq(i)*ones(length(MM.thk),1);zz(:,i)=-cumsum(MM.thk);end;zz2=[zeros(1,P);zz]; 133 | xx2=[zeros(length(MM.thk),1),xx];xx=((xx2(:,1:end-1)+xx2(:,2:end))/2); 134 | zz=((zz2(1:end-1,:)+zz2(2:end,:))/2);%dlmwrite('pmin.dat',pmin);%dlmwrite('pmax.dat',pmax); 135 | nx=length(dx);nz=length(MM.thk); mesh.num_param=nx*nz;mesh.param_x=xx(:); 136 | mesh.param_y=zz(:); 137 | input.time_lapse_flag=0; 138 | dz=MM.thk;dy=dx;%dlmwrite('wta.dat',wta); 139 | wta=wta(:);%wta(wta<1)=0; 140 | mesh=smooth_mtx_surface4444(input,mesh,wta,nx,nz,sx,sz); 141 | nx=length(dx);nz=length(dz);V = spdiags((wta(:)), 0, nx*nz, nx*nz); 142 | [Gx, Gz]=newgradient(dx,dz);als=10;%V=0; 143 | Gs = sx*Gx+sz*Gz; 144 | Wt = spdiags(wta(:),0,nx*nz,nx*nz);wty=ones(length(wta(:)),1);Wty = spdiags(wty(:),0,nx*nz,nx*nz); 145 | MW = Wt' * ( Gs' * Gs + als * V ) * Wt; 146 | MW=mesh.ctc; 147 | pin=pin(:);%reshape(pin,length(pin),1); 148 | mref=mref(:);%reshape(mref,length(mref),1); 149 | %dlmwrite('pin.dat',pin);dlmwrite('mref.dat',mref);dlmwrite('MW.dat',MW); 150 | X = diag( (1./(xc(:)-log10(1/pmin))) + (1./(log10(1/pmax)-xc(:))),0 ); 151 | fm = (xc(:)-mref)'*MW*(xc(:)-mref) + muv*(xc(:)-mref)'*(xc(:)-mref)+(X'*X); 152 | fc =fd+16*fm; 153 | grad_fm = muv*MW*(xc(:)-mref);%dlmwrite('gm.dat',grad_fm); 154 | grad_fd = J'*W'*(G-obs);%dlmwrite('gf.dat',grad_fd); 155 | % Combine the gradients 156 | gc = grad_fd + grad_fm; 157 | %%%% Store some quantities for l/home/melwasei/Desktop/Resistivity2.zip_FILES/Resistivity2ater use 158 | 159 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 160 | rms_error = misfit; 161 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 162 | MTX.mc = xc; 163 | para.intol = 1e-9; % tol for inexact newton solver (ipcg) 164 | para.inintol = 1e-9; % tol for the forward and adjoint problems 165 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 166 | para.init = 4; % number of ipcg iterations 167 | para.ilutol = 1e-2; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 168 | para.alp=1e-4; % Parameter for line search 169 | MTX.WTW=MW;%dlmwrite('J.dat',J); 170 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J,W); 171 | % s=(J'*(W'*W)*J+muv*(MW))\(-(gc)); 172 | % Test for convergence 173 | if max(abs(s)) < 1e-3, 174 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 175 | fprintf('STEP size too small CONVERGE '); % return; 176 | end; 177 | %dlmwrite('s.dat',s); 178 | pin=pin(:); 179 | % Try the step 180 | mu_LS = 1; 181 | iarm = 0; 182 | while 1, 183 | 184 | 185 | xt = xc(:) + mu_LS*s; 186 | 187 | xt=reshape(xt,length(d),length(xt)/length(d));xt=xt; 188 | for ii=1:P,%% Loop over all station positions (B2) 189 | pin=[xt(:,ii)]; 190 | MM.con=xt(:,ii); %dlmwrite('ccon.dat',xt(:,ii)); 191 | if unique(q(:,ii))<2 192 | for i=1:length(f);S.tor{i}='z';end;S.tor=reshape(S.tor,length(f),1); 193 | S.tmom=-1*ones(length(f),1);S.ror=S.tor;S.rmom=S.tmom; 194 | elseif length(unique(q(:,ii)))>1 195 | disp('There is something wrong with coil configuration: review column 7 of input data for consistency'); 196 | return 197 | end 198 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 199 | G_trial(:,ii) = Gout(1:NN); 200 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 201 | end % end (B2) loop over station positions 202 | G_try=G_trial(:);%reshape(G_trial,NP,1); 203 | 204 | 205 | fd = (G-obs)'*(W'*W)*(G-obs); 206 | 207 | %automatically determine a beta guess 208 | if itc == 1 & muv ==0; 209 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 210 | end; 211 | % fm = (xc(:)-mref)'*MW*(xc(:)-mref) + muv*(xc(:)-mref)'*(xc(:)-mref); 212 | fm = (xc(:)-mref)' *(xc(:)-mref)+(X'*X); 213 | ft = fd+fm; 214 | fgoal = fc - para.alp*mu_LS*(s'*gc); 215 | 216 | if ft < fgoal, 217 | break, 218 | else 219 | % break, 220 | iarm = iarm+1; 221 | mu_LS = mu_LS/2; 222 | end; 223 | 224 | 225 | if(iarm > 5) 226 | %disp(' Line search FAIL EXIT(0)'); 227 | break; 228 | end 229 | fgoal = fc - para.alp*mu_LS*(s'*gc); 230 | end % end line search 231 | covdem=W'*W; 232 | [g3, ~]=size(mesh.ctc); 233 | %covdem=diag(ones(length(pobs(:)),1)); 234 | covmem=mesh.ctc'*mesh.ctc; 235 | alphem=1; 236 | N1r=(1/bet(ioo)^2)*J'*covdem*J+(alphem^2)*mesh.ctc'*mesh.ctc+covmem;%dlmwrite('params.dat',params);%dlmwrite('J.dat',J);%dlmwrite('pobs.dat',pobs);%dlmwrite('G.dat',G); 237 | %dlmwrite('covmem.dat',covmem); 238 | n2r=(1/bet(ioo)^2)*J'*covdem*(pobs(:)-G+J*xc(:))+covmem*pree(:); 239 | xc=N1r\n2r;%-(AN1\(AJm'*AL)); 240 | 241 | %xc=1./(10.^xc); 242 | %pmax1=pmin;pmin1=pmax; 243 | %xc(xcpmax)=pmax; 245 | %xc=log10(1./xc); 246 | [gr hr]=size(xt);xc=reshape(xc,gr,hr); 247 | tsum=0; 248 | % Find RMS error 249 | pos=pobs(:); 250 | for iqe=1:length(pos) 251 | tsum=tsum+(((pos(iqe))-(G(iqe))).*((pos(iqe))-(G(iqe))))./((pos(iqe))*(pos(iqe))); 252 | end 253 | rms_sum1=sqrt(tsum/length(pos))*100; 254 | disp(sprintf('RMS Error=>%f %',rms_sum1)); 255 | 256 | 257 | xt = xc; 258 | misfitnew = misfit; 259 | misfitold = misfitnew; 260 | rms_error2(:,itc)=rms_error; 261 | %if sens 262 | JTJ=J'*W*J; 263 | sense=xt(:)\(JTJ);%dlmwrite('sense.dat',sense); 264 | %else 265 | % sense=[]; 266 | %end 267 | if cell_sens 268 | cell_sensy=diag(J'*(W'*W)*J);cell_sensy=cell_sensy./max(cell_sensy); 269 | else 270 | cell_sensy=[]; 271 | end 272 | 273 | end % end loop (A1) over iterations 274 | p_final=xc; 275 | muh_final=muv; 276 | %pmax1=log10(1/pmax); 277 | %pmin1=log10(1/pmin); 278 | %p_final(p_finalpmin1)=pmin1; 280 | 281 | 282 | %save('J.mat','J');save('C.mat','Wt');save('D.mat','W'); 283 | 284 | -------------------------------------------------------------------------------- /Code/FEMIC_tost21.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error2, G,sense]=FEMIC_tost21(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sx,sz,wta,pmin,pmax,coords) 53 | 54 | %% Initialize array size and constant parameters 55 | MM.con(MM.con>0)=log10(MM.con(MM.con>0)); 56 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 57 | szp=size(pobs); % number of frequencies (x2) by number of stations 58 | P=szp(2); % number of data (freq x 2) 59 | %M=length(d); 60 | params=MM.con; 61 | d=MM.thk; 62 | f=S.freq; 63 | r=S.r; 64 | M = length(d);%size(params,1); % number of model parameters 65 | Md = length(d); % number of layer thicknesses 66 | Ms = M-Md; % should be the number of conducitivities 67 | %N=szp(1); 68 | N=length(f); % number of frequencies 69 | if q==3, 70 | NN=2*N; % twice the frequenices if both VDM and HDM used 71 | else 72 | NN=N; % total number of data points (same as N if only one orientation of data is used) 73 | end 74 | NP=NN*P; % size of the data set 75 | MP=M*P; 76 | % size of the model output set 77 | xc=params; 78 | params=repmat(params,1,P);[vr, wr]=size(pobs); 79 | q=q(:);q=q(1:vr*wr); 80 | q=reshape(q,vr,wr);% 81 | obs=pobs(:);%reshape(pobs,NP,1); 82 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 83 | %% Initialize the regularization matrices 84 | W=diag(1./sigma(:));MTX.W=W; 85 | dp=1; 86 | tic; 87 | mref=xc;%muv=muv/100000; 88 | %% Outer loop over maximum number of iterations (breaks if alternate 89 | %% convergence criteria are met 90 | itc = 0; 91 | % Start Gauss-Newton loop 92 | % allocate some numbers 93 | misfit = []; gc = 1; normg0 = 1; 94 | while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 95 | % iteration count 96 | itc = itc+1; 97 | %for i=1:max_iter, % loop over iterations (A1) 98 | 99 | for ii=1:P, % loop over all measurement positions (B1) 100 | fprintf(' Computing profile %3.0f\n',ii) 101 | pin(:,ii)=xc(:,ii); % model input parameters for this position (ii) 102 | %[GG(:,ii),JJ]=jacnmodelMdl_mat(f,r,pin,d); 103 | MM.con=pin(:,ii); 104 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 105 | if unique(q(:,ii))<2 106 | for i=1:length(f);S.tor{i}='z';end;S.tor=reshape(S.tor,length(f),1); 107 | S.tmom=-1*ones(length(f),1);S.ror=S.tor;S.rmom=S.tmom; 108 | elseif length(unique(q(:,ii)))>1 109 | disp('There is something wrong with coil configuration: review column 7 of input data for consistency'); 110 | return; 111 | end 112 | % Compute the model kernel Gout, and Jacobian matrix J 113 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 114 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 115 | %[t,x,y] = sim('jacobianMdl3'); 116 | 117 | GG(:,ii) = Gout;%(1:NN); % place current Gout vector in the global GG array 118 | JJ = Jout;%(1:NN,1:6); % organize the global Jacobian matrix 119 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 120 | end % end (B1) loop over measurement positions 121 | % Reshape G into a vector 122 | G=GG(:);%reshape(GG,NP,1); 123 | 124 | % Compute the Lp (p=porder) rms error 125 | 126 | elap_time=toc/60; 127 | fd =(G-obs)'*(W'*W)*(G-obs); 128 | if itc == 1 & isempty(muv); 129 | %%Temporarily assign a value, to be corrected later 130 | para.BETA = 0; 131 | end; 132 | %wta=1*ones(Md,P); 133 | dx=ones(P,1); 134 | dz=MM.thk;dy=dx; 135 | 136 | wta=wta(:);wta(wta<1)=0; 137 | nx=length(dx);nz=length(dz);V = spdiags((wta(:)), 0, nx*nz, nx*nz); 138 | [Gx, Gz]=newgradient(dx,dz);als=.0011;%V=0; 139 | Gs = sx*Gx+sz*Gz; 140 | sense=diag(J'*(W'*W)*J);sense=flipdim(sense,1); 141 | 142 | %wta=1-wta; 143 | 144 | Wt = spdiags(wta(:),0,nx*nz,nx*nz);wty=ones(length(wta(:)),1);Wty = spdiags(wty(:),0,nx*nz,nx*nz); 145 | MW = Wt' * ( Gs' * Gs + als * V ) * Wt;pin=pin(:);%reshape(pin,length(pin),1); 146 | mref=mref(:);%reshape(mref,length(mref),1); 147 | X = diag( (1./(xc(:)-log10(1/pmin))) + (1./(log10(1/pmax)-xc(:))),0 ); 148 | fm = (xc(:)-mref)'*MW*(xc(:)-mref) + muv*(xc(:)-mref)'*(xc(:)-mref)+(X'*X); 149 | %%Add them for the total Objective function 150 | fc =fd+fm; 151 | 152 | % Evaluate the gradient 153 | % model objective function gradient 154 | 155 | 156 | 157 | 158 | grad_fm = muv*MW*(xc(:)-mref);%dlmwrite('gm.dat',grad_fm); 159 | grad_fd = J'*W'*(G-obs);%dlmwrite('gf.dat',grad_fd); 160 | % Combine the gradients 161 | gc = grad_fd + grad_fm; 162 | %%%% Store some quantities for l/home/melwasei/Desktop/Resistivity2.zip_FILES/Resistivity2ater use 163 | 164 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 165 | rms_error = misfit; 166 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 167 | MTX.mc = xc; 168 | para.intol = 1e-9; % tol for inexact newton solver (ipcg) 169 | para.inintol = 1e-9; % tol for the forward and adjoint problems 170 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 171 | para.init = 4; % number of ipcg iterations 172 | para.ilutol = 1e-2; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 173 | para.alp=1e-4; % Parameter for line search 174 | MTX.WTW=MW;%dlmwrite('J.dat',J); 175 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J,W); 176 | % s=(J'*(W'*W)*J+muv*(MW))\(-(gc)); 177 | % Test for convergence 178 | if max(abs(s)) < 1e-3, 179 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 180 | fprintf('STEP size too small CONVERGE '); % return; 181 | end; 182 | %dlmwrite('s.dat',s); 183 | pin=pin(:); 184 | % Try the step 185 | mu_LS = 1; 186 | iarm = 0; 187 | while 1, 188 | 189 | 190 | xt = xc(:) + mu_LS*s; 191 | %%%% Evaluate the new objective function 192 | 193 | xt=reshape(xt,length(d),length(xt)/length(d));xt=xt; 194 | %pin=reshape(pin,length(d),length(xt)/length(d)); 195 | for ii=1:P,%% Loop over all station positions (B2) 196 | 197 | pin=[xt(:,ii)]; 198 | MM.con=xt(:,ii); %dlmwrite('ccon.dat',xt(:,ii)); 199 | %[G_trial(:,ii),J_trial]=jacnmodelMdl_mat(f,r,pin,d); 200 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 201 | % Compute the model kernel Gout, and Jacobian matrix J 202 | if unique(q(:,ii))<2 203 | for i=1:length(f);S.tor{i}='z';end;S.tor=reshape(S.tor,length(f),1); 204 | S.tmom=-1*ones(length(f),1);S.ror=S.tor;S.rmom=S.tmom; 205 | elseif length(unique(q(:,ii)))>1 206 | disp('There is something wrong with coil configuration: review column 7 of input data for consistency'); 207 | return 208 | end 209 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 210 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 211 | %[G,J] = jacobianMdl_mat_opt_depths(freq,rspa,params,d,N,M,nlayers) 212 | %[t,x,y] = sim('jacobianMdl3'); 213 | G_trial(:,ii) = Gout(1:NN); 214 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 215 | end % end (B2) loop over station positions 216 | G_try=G_trial(:);%reshape(G_trial,NP,1); 217 | 218 | 219 | fd = (G-obs)'*(W'*W)*(G-obs); 220 | 221 | %automatically determine a beta guess 222 | if itc == 1 & muv ==0; 223 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 224 | end; 225 | % fm = (xc(:)-mref)'*MW*(xc(:)-mref) + muv*(xc(:)-mref)'*(xc(:)-mref); 226 | fm = (xc(:)-mref)' *(xc(:)-mref)+(X'*X); 227 | ft = fd+fm; 228 | fgoal = fc - para.alp*mu_LS*(s'*gc); 229 | 230 | if ft < fgoal, 231 | break, 232 | else 233 | % break, 234 | iarm = iarm+1; 235 | mu_LS = mu_LS/2; 236 | end; 237 | 238 | if(iarm > 5) 239 | disp(' Line search FAIL EXIT(0)'); 240 | return; 241 | end 242 | fgoal = fc - para.alp*mu_LS*(s'*gc); 243 | end % end line search 244 | 245 | 246 | % L-Curve 247 | 248 | 249 | xc = xt; 250 | misfitnew = misfit; 251 | misfitold = misfitnew; 252 | rms_error2(:,itc)=rms_error; 253 | 254 | 255 | end % end loop (A1) over iterations 256 | p_final=xt; 257 | muh_final=muv; 258 | 259 | -------------------------------------------------------------------------------- /Code/FEMIC_tost22.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error2, G]=FEMIC_tost22(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sx,sz,wta) 53 | 54 | %% Initialize array size and constant parameters 55 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 56 | szp=size(pobs); % number of frequencies (x2) by number of stations 57 | P=szp(2); % number of data (freq x 2) 58 | params=MM.con; 59 | d=MM.thk; 60 | f=S.freq; 61 | r=S.r; 62 | M = length(d);%size(params,1); % number of model parameters 63 | Md = length(d); % number of layer thicknesses 64 | Ms = M-Md; % should be the number of conducitivities 65 | N=length(f); % number of frequencies 66 | if q==3, 67 | NN=2*N; % twice the frequenices if both VDM and HDM used 68 | else 69 | NN=N; % total number of data points (same as N if only one orientation of data is used) 70 | end 71 | NP=NN*P; % size of the data set 72 | MP=M*P; 73 | % size of the model output set 74 | xc=params; 75 | params=repmat(params,1,P); 76 | 77 | obs=pobs(:);%reshape(pobs,NP,1); 78 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 79 | %% Initialize the regularization matrices 80 | W=diag(1./sigma(:));MTX.W=W; 81 | dp=1; 82 | tic; 83 | mref=xc; 84 | %% Outer loop over maximum number of iterations (breaks if alternate 85 | %% convergence criteria are met 86 | itc = 0; 87 | misfit = []; gc = 1; normg0 = 1; 88 | while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 89 | % iteration count 90 | itc = itc+1; 91 | for ii=1:P, % loop over all measurement positions (B1) 92 | fprintf(' Computing profile %3.0f\n',ii) 93 | pin(:,ii)=xc(:,ii); % model input parameters for this position (ii) 94 | %[GG(:,ii),JJ]=jacnmodelMdl_mat(f,r,pin,d); 95 | MM.con=pin(:,ii); 96 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97 | % Compute the model kernel Gout, and Jacobian matrix J 98 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 99 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 100 | 101 | GG(:,ii) = Gout;%(1:NN); % place current Gout vector in the global GG array 102 | JJ = Jout;%(1:NN,1:6); % organize the global Jacobian matrix 103 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 104 | end % end (B1) loop over measurement positions 105 | % Reshape G into a vector 106 | G=GG(:);%reshape(GG,NP,1); 107 | 108 | elap_time=toc/60; 109 | fd = 0.5*(G-obs)'*(W)*(G-obs); 110 | if itc == 1 & isempty(muv); 111 | %%Temporarily assign a value, to be corrected later 112 | para.BETA = 0; 113 | end; 114 | dx=ones(P,1);dz=MM.thk;%ones(length(MM.thk),1);dy=dx; 115 | nx=length(dx);nz=length(dz);V = spdiags((wta(:)), 0, nx*nz, nx*nz); 116 | [Gx, Gz]=grad2d(dx,dz);als=7;%V=0; 117 | Gs = [sx*Gx;sz*Gz]; 118 | Wt = spdiags(wta(:),0,nx*nz,nx*nz); 119 | MW = Wt' * ( Gs' * Gs + als * V ) * Wt;pin=pin(:);%reshape(pin,length(pin),1); 120 | mref=mref(:);%reshape(mref,length(mref),1); 121 | %dlmwrite('pin.dat',pin);dlmwrite('mref.dat',mref);dlmwrite('MW.dat',MW); 122 | fm = muv*((xc(:)-mref)'*MW*(xc(:)-mref)); 123 | %%Add them for the total Objective function 124 | fc =fd+fm; 125 | 126 | grad_fm = muv*MW*(xc(:)-mref);%dlmwrite('gm.dat',grad_fm); 127 | grad_fd = J'*(G-obs);%dlmwrite('gf.dat',grad_fd); 128 | % Combine the gradients 129 | gc = grad_fd + grad_fm; 130 | %%%% Store some quantities for later use 131 | 132 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 133 | rms_error = misfit; 134 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 135 | MTX.mc = xc; 136 | para.intol = 1e-9; % tol for inexact newton solver (ipcg) 137 | para.inintol = 1e-9; % tol for the forward and adjoint problems 138 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 139 | para.init = 4; % number of ipcg iterations 140 | para.ilutol = 1e-2; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 141 | para.alp=1e-4; % Parameter for line search 142 | MTX.WTW=MW;%dlmwrite('J.dat',J); 143 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J,W); 144 | if max(abs(s)) < 1e-3, 145 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 146 | fprintf('STEP size too small CONVERGE '); % return; 147 | end; 148 | pin=pin(:); 149 | % Try the step 150 | mu_LS = 1; 151 | iarm = 0; 152 | while 1, 153 | 154 | 155 | xt = xc(:) + mu_LS*s; 156 | 157 | xt=reshape(xt,length(d),length(xt)/length(d));xt=xt; 158 | %pin=reshape(pin,length(d),length(xt)/length(d)); 159 | for ii=1:P,%% Loop over all station positions (B2) 160 | pin=[xt(:,ii)]; 161 | MM.con=xt(:,ii); %dlmwrite('ccon.dat',xt(:,ii)); 162 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 163 | G_trial(:,ii) = Gout(1:NN); 164 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 165 | end % end (B2) loop over station positions 166 | G_try=G_trial(:);%reshape(G_trial,NP,1); 167 | 168 | 169 | fd = 0.5*(G_try-obs)'*W*(G_try-obs); 170 | 171 | %automatically determine a beta guess 172 | if itc == 1 & muv ==0; 173 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 174 | end; 175 | fm = 0.5*muv*( (xt(:)-mref)'*muv*(xt(:)-mref)); 176 | ft = fd+fm; 177 | fgoal = fc - para.alp*mu_LS*(s'*gc); 178 | 179 | if ft < fgoal, 180 | break, 181 | else 182 | % break, 183 | iarm = iarm+1; 184 | mu_LS = mu_LS/2; 185 | end; 186 | 187 | if(iarm > 5) 188 | 189 | break, 190 | end 191 | fgoal = fc - para.alp*mu_LS*(s'*gc); 192 | end % end line search 193 | % Update model 194 | 195 | % L-Curve 196 | 197 | 198 | xc = xt; 199 | misfitnew = misfit; 200 | misfitold = misfitnew; 201 | rms_error2(:,itc)=rms_error; 202 | 203 | 204 | end % end loop (A1) over iterations 205 | p_final=xt; 206 | muh_final=muv; 207 | 208 | -------------------------------------------------------------------------------- /Code/FEMIC_tost3.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization) 17 | % 18 | % Originated by: Greg Schultz 19 | % Modified from original codes produced in 2004/2005 20 | % Significantly modifield in 2008 to incorporate the log-barrier function 21 | % constraint to enforce positivity and add a number of other features 22 | % Code delivered to the USGS under PO XXXXXXXXX in June 2008 23 | % 24 | %% 25 | % INPUTS: 26 | % params = model parameters to be optimizaed 27 | % d = depths (initial) (1 x mlayers) 28 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 29 | % sigma = standard deviations on measurements (1 x 2*length(f)) 30 | % f = frequencies 31 | % r = separation distances between Rx and Tx for bistatic case 32 | % muh = horizontal regularization coeffecient 33 | % muv = vertical regularization coeffectient 34 | % tol_eca = tolerance on changes to conductivity 35 | % err_tol = convergence criteria for changing errors 36 | % max_iter = maximum no. of allowable iterations 37 | % q = [=1,2,3] to designate the data types represented in the pobs input 38 | % array: 1=Vertical Magnetic Dipole only 39 | % 2=Horizontal Magnetic Dipole only 40 | % 3=Both VMD and HMD data 41 | %% 42 | % OUTPUTS: 43 | % p_final = the final model array in [P stations x N frequencies (2xN for 44 | % both VMD and HMD data)] form 45 | % muh_final = the final horizontal regulatization coeffecient 46 | % rms_error = the history of the Lp norm rms errors between forward model 47 | % results (G(m)) and data (d) 48 | % 49 | % EXAMPLE USAGE: 50 | % [g,mmu,of,mdata]=inverse_2d_guiCHC_SIMU(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 51 | 52 | function [p_final, muh_final, rms_error2, G]=FEMIC_tost3(MM,S,el,pobs,sigma,muv,err_tol,max_iter,q,sx,sy,sz,wta,pmin,pmax) 53 | 54 | %% Initialize array size and constant parameters 55 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 56 | szp=size(pobs); % number of frequencies (x2) by number of stations 57 | P=size(pobs,2); % number of data (freq x 2)P=size(pobs,2); 58 | PP=size(pobs,3); 59 | PPP=size(pobs,1); 60 | pobs=reshape(pobs,PPP,P*PP); 61 | d=MM.thk; 62 | f=S.freq; 63 | r=S.r; 64 | M = length(d);%size(params,1); % number of model parameters 65 | Md = length(d); % number of layer thicknesses 66 | Ms = M-Md; % should be the number of conducitivities 67 | %N=szp(1); 68 | N=length(f); % number of frequencies 69 | if q==3, 70 | NN=2*N; % twice the frequenices if both VDM and HDM used 71 | else 72 | NN=N; % total number of data points (same as N if only one orientation of data is used) 73 | end 74 | NP=NN*P; % size of the data set 75 | MP=M*P; 76 | % size of the model output set 77 | xc=MM.con;%reshape(params,M,P*PP); 78 | obs=pobs(:);%reshape(pobs,NP,1); 79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 80 | %% Initialize the regularization matrices 81 | sigma=reshape(sigma,PPP,P*PP); 82 | W=diag(1./sigma(:));MTX.W=W; 83 | dp=1; 84 | tic; 85 | mref=xc; 86 | %% Outer loop over maximum number of iterations (breaks if alternate 87 | %% convergence criteria are met 88 | itc = 0; 89 | % Start Gauss-Newton loop 90 | % allocate some numbers 91 | misfit = []; gc = 1; normg0 = 1; 92 | while(norm(gc)/normg0 > err_tol & itc < max_iter & norm(gc)>1e-20) 93 | % iteration count 94 | itc = itc+1; 95 | %for i=1:max_iter, % loop over iterations (A1) 96 | for ii=1:P*PP, % loop over all measurement positions (B1) 97 | fprintf(' Computing profile %3.0f\n',ii) 98 | pin(:,ii)=xc(:,ii); % model input parameters for this position (ii) 99 | MM.con=pin(:,ii); 100 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101 | % Compute the model kernel Gout, and Jacobian matrix J 102 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 103 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 104 | 105 | GG(:,ii) = Gout;%(1:NN); % place current Gout vector in the global GG array 106 | JJ = Jout;%(1:NN,1:6); % organize the global Jacobian matrix 107 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 108 | end % end (B1) loop over measurement positions 109 | % Reshape G into a vector 110 | G=GG(:);%reshape(GG,NP,1); 111 | elap_time=toc/60; 112 | fd = 0.5*(G-obs)'*(W)*(G-obs); 113 | if itc == 1 & isempty(muv); 114 | %%Temporarily assign a value, to be corrected later 115 | para.BETA = 0; 116 | end; 117 | dx=1*ones(P,1);dz=ones(PPP,1);dy=ones(PP,1);%dlmwrite('wt.dat',wta); 118 | nx=length(dx);nz=length(dz);ny=length(dy);V = spdiags((wta(:)), 0, nx*ny*nz, nx*ny*nz); 119 | [Gx, Gy,Gz]=grad3D(dx,dy,dz);als=1;%V=0; 120 | Gs = [sx*Gx;sy*Gy;sz*Gz]; 121 | %wta=1-wta; 122 | Wt = spdiags(wta(:),0,nx*ny*nz,nx*ny*nz); 123 | MW = Wt' * ( Gs' * Gs + als * V ) * Wt;pin=pin(:);%reshape(pin,length(pin),1); 124 | mref=mref(:);%reshape(mref,length(mref),1); 125 | X = diag( (1./(xc(:)-log10(1/pmin))) + (1./(log10(1/pmax)-xc(:))),0 ); 126 | fm = (xc(:)-mref)'*MW*(xc(:)-mref) + muv*(xc(:)-mref)'*(xc(:)-mref)+(X'*X); 127 | %%Add them for the total Objective function 128 | fc =fd+fm; 129 | grad_fm = muv*MW*(xc(:)-mref);%dlmwrite('gm.dat',grad_fm); 130 | grad_fd = J'*(G-obs);%dlmwrite('gf.dat',grad_fd); 131 | % Combine the gradients 132 | gc = grad_fd + grad_fm; 133 | %%%% Store some quantities for later use 134 | 135 | misfit = sqrt((G-obs)'*W*(G-obs))/sqrt(obs'*W*obs); 136 | rms_error = misfit; 137 | if itc == 1, normg0 = norm(gc); f0 = fc; mis0 = misfit; end; 138 | MTX.mc = xc; 139 | para.intol = 0; % tol for inexact newton solver (ipcg) 140 | para.inintol = 1e-9; % tol for the forward and adjoint problems 141 | para.ininintol = 1e-6; % tol for the inner solution in the ipcg 142 | para.init = 4; % number of ipcg iterations 143 | para.ilutol = 0; %ilu preconditioner tolerance, reduce to 1e-3 if you run into memory issues 144 | para.alp=1e-4; % Parameter for line search 145 | MTX.WTW=MW;%dlmwrite('J.dat',J); 146 | s = ipcg(MTX, muv, -gc, para.intol, para.ininintol, para.init,J); 147 | 148 | % Test for convergence 149 | if max(abs(s)) < 1e-3, 150 | fprintf(' max_s = %e, norm(g) = %e\n', max(abs(s)), norm(gc)); 151 | fprintf('STEP size too small CONVERGE '); % return; 152 | end; 153 | %dlmwrite('s.dat',s); 154 | pin=pin(:); 155 | % Try the step 156 | mu_LS = 1; 157 | iarm = 0; 158 | while 1, 159 | 160 | 161 | xt = xc(:) + mu_LS*s; 162 | 163 | xt=reshape(xt,length(d),length(xt)/length(d));xt=xt; 164 | %pin=reshape(pin,length(d),length(xt)/length(d)); 165 | for ii=1:P*PP,%% Loop over all station positions (B2) 166 | 167 | pin=[xt(:,ii)]; 168 | MM.con=xt(:,ii); %dlmwrite('ccon.dat',xt(:,ii)); 169 | %[G_trial(:,ii),J_trial]=jacnmodelMdl_mat(f,r,pin,d); 170 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 171 | % Compute the model kernel Gout, and Jacobian matrix J 172 | [Gout,Jout] =fdem1dfwd(S,MM,el,1); Gout=imag(Gout); Jout=imag(Jout);%[Gout,Jout] = FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 173 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 174 | 175 | G_trial(:,ii) = Gout(1:NN); 176 | 177 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 178 | end % end (B2) loop over station positions 179 | G_try=G_trial(:);%reshape(G_trial,NP,1); 180 | 181 | 182 | fd = 0.5*(G_try-obs)'*W*(G_try-obs); 183 | 184 | %automatically determine a beta guess 185 | if itc == 1 & muv ==0; 186 | para.BETA = 0.5*(fd./( (xt-mref)'*muv*(xt-mref))) 187 | end; 188 | fm = 0.5*muv*( (xt(:)-mref)'*muv*(xt(:)-mref))+(X'*X); 189 | ft = fd+fm; 190 | fgoal = fc - para.alp*mu_LS*(s'*gc); 191 | 192 | if ft < fgoal, 193 | break, 194 | else 195 | % break, 196 | iarm = iarm+1; 197 | mu_LS = mu_LS/2; 198 | end; 199 | 200 | if(iarm > 5) 201 | % disp(' Line search FAIL EXIT(0)'); 202 | % return; 203 | break, 204 | end 205 | fgoal = fc - para.alp*mu_LS*(s'*gc); 206 | end % end line search 207 | % Update model 208 | 209 | % L-Curve 210 | 211 | 212 | xc = xt; 213 | misfitnew = misfit; 214 | misfitold = misfitnew; 215 | rms_error2(:,itc)=rms_error; 216 | 217 | 218 | end % end loop (A1) over iterations 219 | p_final=xt; p_final=reshape(p_final,PPP,P*PP); 220 | muh_final=muv; 221 | 222 | -------------------------------------------------------------------------------- /Code/Figure1-model and data.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/Figure1-model and data.fig -------------------------------------------------------------------------------- /Code/GEM2FEM.m: -------------------------------------------------------------------------------- 1 | function [data] = GEM2FEM(filename) 2 | %this function converts data from the standard GEM2 format to FEMIC 3 | %this will also read the data if the file is already in FEMIC format 4 | %which would be the case for previously filtered data 5 | 6 | 7 | %file = dlmread('EMline1raw.csv') 8 | 9 | %% Open the data file. 10 | fileID = fopen(filename,'r'); %give file an identifier 11 | header = fgets(fileID); %read in header as single charcter string 12 | colnames = strread(header,'%s','delimiter',','); %split the string based on commas 13 | ncol = length(colnames); %number of columns in the header 14 | 15 | %find the file extension - currently .csv is used for the unfiltered and .dat is used for the filtered 16 | ext = []; %start with empty vector 17 | for index=length(filename):-1:1 %loop backwards through filename 18 | if (filename(index) == '.') %break out of loop when '.' is encountered 19 | break; 20 | end 21 | ext = strcat(filename(index),ext); %while in loop put letters of extension in 'ext' 22 | end 23 | 24 | if (ext == 'csv') %then this is a raw GEM2 file 25 | headerSpec = repmat('%s',1,ncol); %26 strings to be read in header line 26 | dataSpec = repmat('%f64',1,ncol); %26 strings to be read in header line 27 | dataArray= textscan(fileID, dataSpec, 'delimiter', ','); %data 28 | sizedata = size(cell2mat(dataArray)); %number of rows and columns in the data 29 | nrows = sizedata(1); 30 | fclose(fileID); %% Close the text file. 31 | save('dataArray.mat','dataArray'); 32 | %find the frequency info 33 | freq_find = strfind(header, 'Hz'); %find number of frequencies /2 for imaginary and quadrature components 34 | nfreq = length(freq_find); 35 | 36 | freq = zeros(1,nfreq); %holds the actual frequencies 37 | k = 1; %counting variable 38 | 39 | for ii = freq_find 40 | fr = []; %start with empty vector to hold character string 41 | for jj = (ii-1):-1:(ii-10) %search backwards from 'Hz' to a maximum of 10 characters to get frequency 42 | if (header(jj) == '_') %break out of loop when '_' is encountered 43 | break; 44 | end 45 | fr = strcat(header(jj),fr); %while in loop put letters of extension in 'fr' 46 | end 47 | f(k) = str2num(fr); %convert character string to numeric 48 | k = k + 1; 49 | end 50 | 51 | 52 | f = unique(f); %get rid of repeats (since there are quadrature and imaginary components to each freq) 53 | nfreq = length(f); %the total number of frequencies 54 | freq = zeros(nfreq,nrows); 55 | %% Post processing for unimportable data. 56 | % No unimportable data rules were applied during the import, so no post 57 | % processing code is included. To generate code which works for 58 | % unimportable data, select unimportable cells in a file and regenerate the 59 | % script. 60 | 61 | %% Allocate imported array to column variable names 62 | X = repmat(dataArray{:, 3},1,nfreq)'; 63 | Y = repmat(dataArray{:, 4},1,nfreq)'; 64 | freq = repmat(f,1,nrows); 65 | id = repmat(1:nrows,nfreq,1); 66 | 67 | k = 12; 68 | dt = []; 69 | for ii=1:nfreq 70 | inphase = dataArray{:,k}; 71 | k = k + 1; 72 | quadrature = dataArray{:,k}; 73 | k = k + 1; 74 | d = complex(inphase, quadrature); 75 | dt = [dt d]; 76 | end 77 | 78 | dt = dt'; 79 | data(:,1)=X(:); 80 | data(:,2)=Y(:); 81 | data(:,3)=zeros(length(data(:,1)),1); 82 | data(:,4)=id(:); 83 | data(:,5)=freq(:); 84 | data(:,6)=ones(length(data(:,1)),1); 85 | data(:,7)=(2.*data(:,6)); 86 | data(:,8)=dt(:); 87 | %dlmwrite('data.dat','data'); 88 | save('dataArray.mat','dataArray'); 89 | elseif (ext == 'dat') %then this is a filtered file already in FEMIC format 90 | data = csvread(filename); %simple data read in 91 | nfreq = unique(data(:,5)); %number of frequencies 92 | %renumber soundings 93 | [uniqueid,I,I2] = unique(data(:,4)); 94 | data(:,4) = I2; 95 | %sort data by sounding ID, then frequency to make things simpler 96 | [sortdata,I] = sortrows(data(:,[4 5])); 97 | data = data(I,:); 98 | fclose(fileID); %% Close the text file. 99 | else 100 | msgbox('The file is in an uknown format'); 101 | end 102 | -------------------------------------------------------------------------------- /Code/J0_120pt.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/J0_120pt.mat -------------------------------------------------------------------------------- /Code/J0_61pt.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/J0_61pt.mat -------------------------------------------------------------------------------- /Code/J1_140pt.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/J1_140pt.mat -------------------------------------------------------------------------------- /Code/J1_47pt.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/J1_47pt.mat -------------------------------------------------------------------------------- /Code/Last1D.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization, Discrepancy, or Max Entropy) 17 | % 18 | 19 | % See Refrence: Schultz and Ruppel, 2005, Geophysics 20 | % Also see FEMIC code technical note and manual, 2008 21 | % 22 | % Originated by: Greg Schultz 23 | % Modified from original codes produced in 2004/2008 24 | % Significantly modifield in 2008 to incorporate the log-barrier function 25 | % constraint to enforce positivity and add a number of other features 26 | % Code delivered to the USGS-Storrs in June 2008 27 | % 28 | %% 29 | % INPUTS: 30 | % params = model parameters to be optimizaed 31 | % d = depths (initial) (1 x mlayers) 32 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 33 | % sigma = standard deviations on measurements (1 x 2*length(f)) 34 | % f = frequencies 35 | % r = separation distances between Rx and Tx for bistatic case 36 | % muh = horizontal regularization coeffecient 37 | % muv = vertical regularization coeffectient 38 | % tol_eca = tolerance on changes to conductivity 39 | % err_tol = convergence criteria for changing errors 40 | % max_iter = maximum no. of allowable iterations 41 | % q = [=1,2,3] to designate the data types represented in the pobs input 42 | % array: 1=Vertical Magnetic Dipole only 43 | % 2=Horizontal Magnetic Dipole only 44 | % 3=Both VMD and HMD data 45 | %// Inputs are generally specificied by the Matlab GUI code FEMIC_InvGUI.m 46 | %% 47 | % OUTPUTS: 48 | % p_final = the final model array in [P stations x N frequencies (2xN for 49 | % both VMD and HMD data)] form 50 | % muh_final = the final horizontal regulatization coeffecient 51 | % rms_error = the history of the Lp norm rms errors between forward model 52 | % results (G(m)) and data (d) 53 | % 54 | % EXAMPLE USAGE: 55 | % [p,mu,errRMS,g]=FEMIC_inverse2D(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 56 | 57 | function [p_final, rms_error, G, best_index]=Last1D(Ma,S,pobs,el,sigma,muh,muv,... 58 | tol_eca,err_tol,max_iter,q,pmin,pmax,barrier,invType) 59 | LCURVEf = 0; % Initialize LCURVE method to DEFAULT (=not used) 60 | initmodel_cond=Ma.con; 61 | init_lyrthick=Ma.thk; 62 | f=S.freq; 63 | r=S.r; 64 | params=initmodel_cond; 65 | d=init_lyrthick; 66 | porder = 2; % norm order (p-value) for error calc (p=2 -> L2 norm) 67 | szp=size(pobs); % number of frequencies (x2) by number of stations 68 | P=szp(2); % number of data (freq x 2) 69 | M = length(params); % number of model parameters 70 | Md = length(d); % number of layer thicknesses 71 | Ms = M-Md; % should be the number of conducitivities 72 | N=length(f); % number of frequencies 73 | if q==3, 74 | NN=2*N; % twice the frequenices if both VDM and HDM used 75 | else 76 | NN=N; % total number of data points (same as N if only one orientation of data is used) 77 | end 78 | NP=NN*P; % size of the data set 79 | MP=M*P; % size of the model output set 80 | params=(repmat(params,1,P)); 81 | obs=pobs(:);%(reshape(pobs,NP,1)); 82 | deltav = -diag(ones((M)*P,1))+diag(ones((M)*P-P,1),P); 83 | deltah = -diag(ones((M)*P,1))+diag(ones((M)*P-1,1),1); 84 | sigma=sigma(:);%reshape(sigma, NP, 1); 85 | po=(params(1:M,:)); 86 | W=diag(1./sigma); 87 | dp=1; 88 | tic; 89 | switch invType 90 | case(1), 91 | inversionTypechar = 'Occams Inversion (Fixed Reg. Coeff.)\n'; 92 | case(2), 93 | inversionTypechar = 'Truncated SVD (Discrepancy Principle)\n'; 94 | case(3) 95 | inversionTypechar = 'Maximum Entropy\n'; 96 | case(4), 97 | inversionTypechar = 'Occams Inversion (L-curve)\n'; 98 | case (5) 99 | inversionTypechar = 'Biconjugate gradient stabilizing method\n'; 100 | otherwise 101 | inversionTypechar = 'Unkwown Inversion Method!!!\n'; 102 | end 103 | fprintf('****** STARTING FEMIC INVERSION ******\n'); 104 | fprintf([' Inversion Type: ',inversionTypechar]); 105 | fprintf(' Maximum Iterations: %i; Error Tolerance: %f; Model Change Tolerance: %f\n',max_iter,err_tol,tol_eca); 106 | 107 | for i=1:max_iter, % loop over iterations (A1) 108 | for ii=1:P, % loop over all measurement positions (B1) 109 | fprintf(' Computing profile %3.0f\n',ii) 110 | pin(:,i)=[po(:,ii)]; % model input parameters for this position (ii) 111 | Ma.con=((pin(:,i))); 112 | [Gout,Jout] =fdem1dfwd(S,Ma,el,1); Gout=(imag(Gout));%./real(Gout); 113 | Jout=(imag(Jout));%./real(Jout);%dlmwrite('J.dat',Gout);%sqrt((imag(Jout)).^2 + (imag(Jout)).^2);%FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 114 | GG(:,ii) = Gout(1:NN); % place current Gout vector in the global GG array 115 | JJ = Jout(1:NN,1:M); % organize the global Jacobian matrix 116 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 117 | end % end (B1) loop over measurement positions 118 | G(:,i)=GG(:); 119 | rms_error(i) = norm(W*G(:,i)-W*obs,porder)/sqrt(length(G(:,i))); 120 | elap_time=toc/60; 121 | fprintf(' Iteration Number: %2.0f rms error: %3.3f Elasped time (mins): %3.2f\n',i,(rms_error(i)),elap_time); 122 | 123 | hj=1;vj=1; 124 | if length(muv)>=length(muh), mu=muv; else mu=muh; end 125 | for j=1:length(mu), % Loop over all regularization coeffecients (C1) 126 | ppo=reshape(po,MP,1);% reorder the the model parameters into a vector 127 | X = diag( (1./(ppo-pmin)) + (1./(pmax-ppo)),0 );dlmwrite('x.dat',X); 128 | 129 | A = muv(j)*deltav'*deltav + muh(j)*deltah'*deltah + (W*J)'*(W*J);%+ barrier.*(X); 130 | 131 | b = (W*J)'*W*(obs - G(:,i) + J*ppo); 132 | switch invType 133 | case(1), 134 | p_trial(:,j)=(A\b); 135 | case(2), 136 | [U,s,V] = FEMIC_svd(A); 137 | [p_trial(:,j),mul]=FEMIC_discrep(U,s,V,b,err_tol/i,ppo); 138 | mu = mul; 139 | case(3), 140 | [p_trial(:,j)] = FEMIC_maxentropy(A,b,mu(j),1,ppo); 141 | case(4), 142 | p_trial(:,j)=(A\b); 143 | LCURVEf=1; 144 | case (5) 145 | p = symrcm(A); 146 | [iii,up] = sort(p); 147 | [PL,PU] = luinc(sparse(A), 1e-4); 148 | p_trial(:,j) = bicgstb(A, b, PL, PU, 500, 1e-9); 149 | otherwise 150 | fprintf('ERROR: No proper inversion method selected\n'); 151 | return 152 | end 153 | lbf = 2*barrier*sum( (log(ppo-pmin)+log(pmax-ppo)) ); 154 | ptemp=(reshape(p_trial(:,j),M,P)); % vector format for temporary trial model parameters 155 | dlmwrite('ptemp.dat',ptemp); 156 | 157 | for ii=1:P,%% Loop over all station positions (B2) 158 | pin2=(ptemp(:,ii)); 159 | Ma.con=((pin2)); 160 | [Gout,Jout] = fdem1dfwd(S,Ma,el,1); Gout=(imag(Gout));%./real(Gout); 161 | Jout=(imag(Jout));%./real(Jout);%sqrt((imag(Jout)).^2 + (imag(Jout)).^2); %FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 162 | 163 | G_trial(:,ii) = Gout(1:NN); 164 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 165 | end % end (B2) loop over station positions 166 | G_try(:,j)=reshape(G_trial,NP,1); 167 | rms_trial(j) = norm(W*G_try(:,j)-W*obs, porder)/sqrt(length(G_try(:,j))); 168 | if LCURVEf & length(mu)>3, % needs at least 4 points to find L-curve 169 | residual_norm(j) = rms_trial(j)*sqrt(length(G_try(:,j))); 170 | solution_norm(j) = mu(j); 171 | end 172 | if length(muv)>=length(muh), vj=vj+1; else hj=hj+1; end 173 | end % end loop (C1) over all regularization coeffecients (C1) 174 | barrier = barrier./5;%((rms_error(i)-rms_trial(j))/rms_error(i)) ) 175 | % Evaluate error tolerance in rms errors 176 | aq1=sum(G);aq2=sum(G_try);aq3=find(aq1<-0.01);aq4=find(aq2<-0.01); 177 | rms_error(isnan(rms_error))=100000000; 178 | rms_trial(isnan(rms_trial))=100000000; 179 | rms_error(aq3)=100000000; 180 | rms_trial(aq4)=100000000; 181 | 182 | if min(rms_trial) > err_tol, 183 | [best_rms, best_index] = min(rms_trial); 184 | 185 | else 186 | 187 | index = find(rms_trial <= err_tol); 188 | if isempty(index) 189 | %rms_trial(isnan(rms_trial))=100000000000; 190 | [best_rms, best_index] = min(rms_trial); 191 | p_final = p_trial(:,best_index); 192 | rms_error(i+1) = best_rms; 193 | G(:,i+1) = G_try(:,best_index); 194 | mu_final = mu(best_index); 195 | return; 196 | 197 | end 198 | end 199 | pnew = p_trial(:,best_index); 200 | rms_vs_chg = norm((pnew' - po')./po')/sqrt(length(po')); 201 | if i==1 202 | if rms_vs_chg < tol_eca | (best_rms <= err_tol) | (i==max_iter) 203 | [best_rms, best_index] = min(rms_error); 204 | p_final =(pin(:,best_index)); 205 | rms_error(i+1) = best_rms; 206 | G(:,i+1) = G(:,best_index); 207 | fprintf('!!******* Model Sequence Completed Successfully **********!!\n') 208 | return; 209 | end 210 | else 211 | chg=(abs(rms_error(i-1)-rms_error(i)))/rms_error(i-1); 212 | if rms_vs_chg < tol_eca | (best_rms <= err_tol) | (i==max_iter) | chg<0.1 %| rms_error(i)>rms_error(i-1) 213 | [best_rms, best_index] = min(rms_error); 214 | p_final = (pin(:,best_index)); 215 | rms_error(i+1) = best_rms; 216 | G(:,i+1) = G(:,best_index); 217 | fprintf('!!******* Model Sequence Completed Successfully **********!!\n') 218 | 219 | return; 220 | end 221 | end 222 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223 | %% L-curve Determination of Regularization coeffecient 224 | if LCURVEf, 225 | if length(mu)>3, 226 | % Use cubic spline interpolant to creat L-curve at 351 points 227 | [nresid_norm, nsoln_norm] = cubicSpline([residual_norm' solution_norm'],32); 228 | % Use Hansen et al., 2007 pruning algorithm to find the "corner" of 229 | % the L-curve 230 | [k_corner,info] = FEMIC_corner(nresid_norm, nsoln_norm); 231 | new_mu = nsoln_norm(k_corner); 232 | if isempty(new_mu), new_mu=mu; end 233 | mu = [new_mu/20;new_mu/8;new_mu/4;4*new_mu;8*new_mu;20*new_mu]; 234 | if length(muv)>length(muh), muv=mu; else muh=mu; end 235 | end 236 | end 237 | 238 | 239 | po=((pnew)); %Ma.con=(ptemp); 240 | end % end loop (A1) over iterations 241 | 242 | -------------------------------------------------------------------------------- /Code/Last2D.m: -------------------------------------------------------------------------------- 1 | % FUNCTION FEMIC_inverse2D.m 2 | % 3 | % This function conmputes the weighted nonlinear least-squares inverse via a 4 | % modified Levenberg-Marquardt scheme with regularized smoothing 5 | % constraints. Added regularization for smoothing are selected by user to 6 | % produce 2D electrical conducttivity models from frequency-domain EM data. 7 | % The 2D regularization constraint formulation is similar to the that 8 | % developed by Constable et al. for inversion of magnetotellurics data. 9 | % 10 | % The inverse model iteratively call the forward model function 11 | % FEMIC_Jacobian.m until the convergence criteria are met. The modified LM 12 | % objective function ||d-G(m)||p + muh(R) + muv(R) + (gamma/2)(X) are 13 | % linearized using Taylor-series expansion and lead to: 14 | % A= muv(deltaV'*deltaV)+muh(deltaH'*deltaH)+(gamma/2)*X*'X+(W*J)'*(W*J) 15 | % b=(W*J')*W*(d-G+J*dp)+(gamma/2)*(X'*X) 16 | % where p_trial = A\b (by Cholesky factorization, Discrepancy, or Max Entropy) 17 | % 18 | % See Refrence: Schultz and Ruppel, 2005, Geophysics 19 | % Also see FEMIC code technical note and manual, 2008 20 | % 21 | % Originated by: Greg Schultz 22 | % Modified from original codes produced in 2004/2008 23 | % Significantly modifield in 2008 to incorporate the log-barrier function 24 | % constraint to enforce positivity and add a number of other features 25 | % Code delivered to the USGS-Storrs in June 2008 26 | % 27 | %% 28 | % INPUTS: 29 | % params = model parameters to be optimizaed 30 | % d = depths (initial) (1 x mlayers) 31 | % pobs = measurements (expected to be VDM cat HDM both (1 x 2*length(f)) 32 | % sigma = standard deviations on measurements (1 x 2*length(f)) 33 | % f = frequencies 34 | % r = separation distances between Rx and Tx for bistatic case 35 | % muh = horizontal regularization coeffecient 36 | % muv = vertical regularization coeffectient 37 | % tol_eca = tolerance on changes to conductivity 38 | % err_tol = convergence criteria for changing errors 39 | % max_iter = maximum no. of allowable iterations 40 | % q = [=1,2,3] to designate the data types represented in the pobs input 41 | % array: 1=Vertical Magnetic Dipole only 42 | % 2=Horizontal Magnetic Dipole only 43 | % 3=Both VMD and HMD data 44 | %// Inputs are generally specificied by the Matlab GUI code FEMIC_InvGUI.m 45 | %% 46 | % OUTPUTS: 47 | % p_final = the final model array in [P stations x N frequencies (2xN for 48 | % both VMD and HMD data)] form 49 | % muh_final = the final horizontal regulatization coeffecient 50 | % rms_error = the history of the Lp norm rms errors between forward model 51 | % results (G(m)) and data (d) 52 | % 53 | % EXAMPLE USAGE: 54 | % [p,mu,errRMS,g]=FEMIC_inverse2D(params,d,pobs,sigma,f,r,muh,muv,tol_eca,err_tol,max_iter,q); 55 | 56 | function [p_final, rms_error, G, best_index]=Last2D(Ma,S,initmodel_cond,init_lyrthick,pobs,el,sigma,muh,muv,... 57 | tol_eca,err_tol,max_iter,q,pmin,pmax,barrier,invType) 58 | LCURVEf = 0; % Initialize LCURVE method to DEFAULT (=not used) 59 | priori=[]; 60 | sx=3; 61 | sz=1; 62 | f=S.freq;r=S.r; 63 | boo=init_lyrthick; 64 | sigma=sigma(:); 65 | for i=1:length(initmodel_cond) 66 | aaaa(i)=length(initmodel_cond{i}); 67 | boo{i}=zeros(length(boo{i}),1); 68 | end 69 | for i=1:length(initmodel_cond) 70 | 71 | if length(initmodel_cond{i}) L2 norm) 89 | P=size(pobs,2); % number of frequencies (x2) by number of stations 90 | PP=size(pobs,1); % number of data (freq x 2) 91 | %M=length(d); 92 | M = size(params,1); % number of model parameters 93 | Md = size(d,1); % number of layer thicknesses 94 | Ms = M-Md; % should be the number of conducitivities 95 | %N=szp(1); 96 | N=length(f); % number of frequencies 97 | if q==3, 98 | NN=2*N; % twice the frequenices if both VDM and HDM used 99 | else 100 | NN=N; % total number of data points (same as N if only one orientation of data is used) 101 | end 102 | NP=NN*P; % size of the data set 103 | MP=M*P; % size of the model output set 104 | wta=zeros(Md,P); 105 | dx=ones(P,1);dz=ones(Md,1);nx=length(dx);nz=length(dz); 106 | [faa fo]=size(priori); 107 | for lo=1:faa 108 | ll=priori(lo,1); 109 | qq=priori(lo,2); 110 | params(qq,ll)=priori(lo,3); 111 | wta(qq,ll)=priori(lo,4); 112 | end 113 | obs=(reshape(pobs,NP,1)); 114 | [Gx Gz]=grad(dx,dz); 115 | Gs = [sx*Gx;sz*Gz]; 116 | wta=1-wta; 117 | Wt = spdiags(wta(:),0,nx*nz,nx*nz); 118 | MW = Wt' * ( Gs' * Gs) * Wt; 119 | %sigma=repmat(sigma, P, 1); 120 | po=params(1:M,:); 121 | 122 | W=diag(1./sigma); 123 | dp=1; 124 | tic; 125 | switch invType 126 | case(1), 127 | inversionTypechar = 'Occams Inversion (Fixed Reg. Coeff.)\n'; 128 | case(2), 129 | inversionTypechar = 'Truncated SVD (Discrepancy Principle)\n'; 130 | case(3) 131 | inversionTypechar = 'Maximum Entropy\n'; 132 | case(4), 133 | inversionTypechar = 'Occams Inversion (L-curve)\n'; 134 | case (5) 135 | inversionTypechar = 'Biconjugate gradient stabilizing method\n'; 136 | otherwise 137 | inversionTypechar = 'Unkwown Inversion Method!!!\n'; 138 | end 139 | fprintf('****** STARTING FEMIC INVERSION ******\n'); 140 | fprintf([' Inversion Type: ',inversionTypechar]); 141 | fprintf(' Maximum Iterations: %i; Error Tolerance: %f; Model Change Tolerance: %f\n',max_iter,err_tol,tol_eca); 142 | %% Outer loop over maximum number of iterations (breaks if alternate 143 | % convergence criteria are met) 144 | for i=1:max_iter, % loop over iterations (A1) 145 | for ii=1:P, % loop over all measurement positions (B1) 146 | fprintf(' Computing profile %3.0f\n',ii) 147 | %pin2(:,i)=po(1:M); 148 | pin(:,:,i)=[po]; % model input parameters for this position (ii) 149 | pin2=po(:,ii); 150 | Ma.con=pin2;Ma.thk=init_lyrthick{ii}; 151 | [Gout,Jout] =fdem1dfwd(S,Ma,el,1); Gout=(imag(Gout)); Jout=(imag(Jout));%dlmwrite('J.dat',Gout);%sqrt((imag(Jout)).^2 + (imag(Jout)).^2);%FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 152 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153 | GG(:,ii) = Gout(1:NN); % place current Gout vector in the global GG array 154 | JJ = Jout(1:NN,1:M); % organize the global Jacobian matrix 155 | J((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=JJ(:,1:M); % reorder Jacobian 156 | end % end (B1) loop over measurement positions 157 | 158 | G(:,i)=GG(:); 159 | % Compute the Lp (p=porder) rms error 160 | rms_error(i) = norm(W*G(:,i)-W*obs,porder)/sqrt(length(G(:,i))); 161 | elap_time=toc/60; 162 | fprintf(' Iteration Number: %2.0f rms error: %3.3f Elasped time (mins): %3.2f\n',i,(rms_error(i)),elap_time); 163 | 164 | 165 | hj=1;vj=1; 166 | if length(muv)>=length(muh), mu=muv; else mu=muh; end 167 | for j=1:length(mu), % Loop over all regularization coeffecients (C1) 168 | ppo=reshape(po,MP,1);% reorder the the model parameters into a vector 169 | 170 | 171 | X = diag( (1./(ppo-pmin)) + (1./(pmax-ppo)),0 );%dlmwrite('x.dat',X); 172 | 173 | A = muv(j)*MW' + (W*J)'*(W*J);% + barrier.*X; 174 | 175 | b = (W*J)'*W*(obs - G(:,i) + J*ppo); 176 | switch invType 177 | case(1), 178 | p_trial(:,j)=(A\b); 179 | case(2), 180 | [U,s,V] = FEMIC_svd(A); 181 | [p_trial(:,j),mul]=FEMIC_discrep(U,s,V,b,err_tol/i,ppo); 182 | mu = mul; 183 | case(3), 184 | [p_trial(:,j)] = FEMIC_maxentropy(A,b,mu(j),1,ppo); 185 | case(4), 186 | p_trial(:,j)=(A\b); 187 | LCURVEf=1; 188 | case (5) 189 | p = symrcm(A); 190 | [iii,up] = sort(p); 191 | [PL,PU] = luinc(sparse(A), 1e-4); 192 | p_trial(:,j) = bicgstb(A, b, PL, PU, 500, 1e-9); 193 | otherwise 194 | fprintf('ERROR: No proper inversion method selected\n'); 195 | return 196 | end 197 | lbf = 2*barrier*sum( (log(ppo-pmin)+log(pmax-ppo)) ); 198 | ptemp=(reshape(p_trial(:,j),M,P)); % vector format for temporary trial model parameters 199 | 200 | for ii=1:P,%% Loop over all station positions (B2) 201 | pin2=(ptemp(:,ii)); 202 | Ma.con=(pin2);Ma.thk=init_lyrthick{ii}; 203 | [Gout,Jout] = fdem1dfwd(S,Ma,el,1); Gout=(imag(Gout)); Jout=(imag(Jout));%sqrt((imag(Jout)).^2 + (imag(Jout)).^2); %FEMIC_JacobianMdl(f,r,pin,d,N,M,Md,q); 204 | G_trial(:,ii) = Gout(1:NN); 205 | J_trial((ii-1)*NN+(1:NN),(ii-1)*(M)+(1:M))=Jout(1:NN,1:M); 206 | end % end (B2) loop over station positions 207 | G_try(:,j)=reshape(G_trial,NP,1); 208 | rms_trial(j) = norm(W*G_try(:,j)-W*obs, porder)/sqrt(length(G_try(:,j))); 209 | %keyboard 210 | if LCURVEf & length(mu)>3, % needs at least 4 points to find L-curve 211 | residual_norm(j) = rms_trial(j)*sqrt(length(G_try(:,j))); 212 | solution_norm(j) = mu(j); 213 | end 214 | if length(muv)>=length(muh), vj=vj+1; else hj=hj+1; end 215 | end % end loop (C1) over all regularization coeffecients (C1) 216 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 217 | 218 | %% Compute convergence criteria 219 | barrier = barrier./5;%((rms_error(i)-rms_trial(j))/rms_error(i)) ) 220 | aq1=sum(G);aq2=sum(G_try);aq3=find(aq1<-0.01);aq4=find(aq2<-0.01); 221 | rms_error(isnan(rms_error))=100000000; 222 | rms_trial(isnan(rms_trial))=100000000; 223 | rms_error(aq3)=100000000; 224 | rms_trial(aq4)=100000000; 225 | 226 | if min(rms_trial) > err_tol, 227 | [best_rms, best_index] = min(rms_trial); 228 | 229 | else 230 | 231 | index = find(rms_trial <= err_tol); 232 | pnew = p_trial(:,index(1)); 233 | if isempty(index) 234 | [best_rms, best_index] = min(rms_trial); 235 | p_final = p_trial(:,best_index); 236 | rms_error(i+1) = best_rms; 237 | G(:,i+1) = G_try(:,best_index); 238 | mu_final = mu(best_index); 239 | return; 240 | 241 | end 242 | 243 | end 244 | pnew = p_trial(:,best_index); 245 | rms_vs_chg = norm((pnew' - po(:)')./po(:)')/sqrt(length(po(:)')); 246 | if i==1 247 | if rms_vs_chg < tol_eca | (best_rms <= err_tol) | (i==max_iter) 248 | [best_rms, best_index] = min(rms_error); 249 | p_final =(pin(:,:,best_index)); 250 | rms_error(i+1) = best_rms; 251 | G(:,i+1) = G(:,best_index); 252 | fprintf('!!******* Model Sequence Completed Successfully **********!!\n') 253 | 254 | return; 255 | end 256 | else 257 | chg=(abs(rms_error(i-1)-rms_error(i)))/rms_error(i-1); 258 | if rms_vs_chg < tol_eca | (best_rms <= err_tol) | (i==max_iter) | chg<0.01 %| rms_error(i)>rms_error(i-1) 259 | [best_rms, best_index] = min(rms_error); 260 | pnew= (pin(:,:,best_index)); 261 | baa= shiftdim(pnew(find(wta))); 262 | da = params; 263 | da(find(wta)) = baa;%pnew; 264 | pnew = da; 265 | p_final = pnew; 266 | rms_error(i+1) = best_rms; 267 | G(:,i+1) = G(:,best_index); 268 | fprintf('!!******* Model Sequence Completed Successfully **********!!\n') 269 | 270 | return; 271 | end 272 | end 273 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 274 | %% L-curve Determination of Regularization coeffecient 275 | if LCURVEf, 276 | if length(mu)>3, 277 | [nresid_norm, nsoln_norm] = cubicSpline([residual_norm' solution_norm'],32); 278 | 279 | [k_corner,info] = FEMIC_corner(nresid_norm, nsoln_norm); 280 | 281 | new_mu = nsoln_norm(k_corner); 282 | if isempty(new_mu), new_mu=mu; end 283 | mu = [new_mu/20;new_mu/8;new_mu/4;4*new_mu;8*new_mu;20*new_mu]; 284 | if length(muv)>length(muh), muv=mu; else muh=mu; end 285 | end 286 | end 287 | 288 | 289 | %% 290 | po=reshape(pnew,M,P); %Ma.con=(ptemp); 291 | end % end loop (A1) over iterations 292 | 293 | -------------------------------------------------------------------------------- /Code/R2.dat: -------------------------------------------------------------------------------- 1 | 0.0046088,0.0095122,0.029363,0.041252,0.033362,0.016417 2 | 0.0067285,0.0016193,0.020139,0.0080232,0.022673,0.0033665 3 | 0.018682,0.0080843,0.02192,0.077305,0.029962,0.0067336 4 | 0.04067,0.033061,0.018955,0.12101,0.011476,0.019657 5 | 0.055547,0.055461,0.063984,0.11161,0.06355,0.054473 6 | 0.031589,0.040167,0.071745,0.048166,0.081618,0.056816 7 | 0.070691,0.054992,0.0034044,0.079619,0.015132,0.023595 8 | 0.28833,0.26989,0.20689,0.30546,0.18582,0.23442 9 | 0.64186,0.62636,0.5641,0.66306,0.54892,0.6017 10 | 1.1212,1.1124,1.06,1.155,1.0585,1.1119 11 | 1.6775,1.6748,1.6333,1.7368,1.6496,1.7054 12 | 2.2254,2.2254,2.1885,2.3192,2.2222,2.2851 13 | 2.661,2.6607,2.6247,2.7822,2.6708,2.7405 14 | 2.8939,2.8924,2.8726,3.0035,2.924,2.9791 15 | -------------------------------------------------------------------------------- /Code/bicgstb.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/bicgstb.m -------------------------------------------------------------------------------- /Code/calcHxx.m: -------------------------------------------------------------------------------- 1 | % Modified by Akbar 2 | function [Hxx,H0xx] = calcHxx(ix,S,z,rTE,u0,lambda); 3 | %%VCX 4 | % B. Minsley, March 2010 5 | 6 | %f(r) = int(K(lam)*Ji(lam*r)dlam 7 | %r*f(r) = sum(K(lam)*W) 8 | 9 | % decompose 10 | w.j0 = lambda.j0.w(:); 11 | flen.j0 = lambda.j0.flen; 12 | lam.j0 = lambda.j0.lam(ix,:); 13 | 14 | w.j1 = lambda.j1.w(:); 15 | flen.j1 = lambda.j1.flen; 16 | lam.j1 = lambda.j1.lam(ix,:); 17 | 18 | % z is positive downwards 19 | h = -(z + S.tzoff(ix)); % transmitter height 20 | rz = z + S.rzoff(ix); % receiver elevation 21 | % Function that changed can be seen as text, Akbar 22 | 23 | %H.j0 = repmat(h,1,flen.j0); 24 | H.j0 = h(:,ones(1,flen.j0)); 25 | 26 | %Z.j0 = repmat(rz,1,flen.j0); 27 | Z.j0 = rz(:,ones(1,flen.j0)); 28 | 29 | %H.j1 = repmat(h,1,flen.j1); 30 | H.j1 = h(:,ones(1,flen.j1)); 31 | 32 | %Z.j1 = repmat(rz,1,flen.j1); 33 | Z.j1 = rz(:,ones(1,flen.j1)); 34 | 35 | % truncate 36 | u0.j0 = u0.j0(ix,:); 37 | rTE.j0 = rTE.j0(ix,:); 38 | tmom = S.tmom(ix); 39 | 40 | u0.j1 = u0.j1(ix,:); 41 | rTE.j1 = rTE.j1(ix,:); 42 | 43 | 44 | % K(lam) - eqn. 4.46 45 | K.j1 = ( exp(-lam.j1.*(Z.j1+H.j1)) - rTE.j1 .* exp(lam.j1.*(Z.j1-H.j1)) ) .* (lam.j1); 46 | K.j0 = ( exp(-lam.j0.*(Z.j0+H.j0)) - rTE.j0 .* exp(lam.j0.*(Z.j0-H.j0)) ) .* (lam.j0).^2; 47 | 48 | Hxxj1 = -(tmom/(4*pi)) .* ( (1./S.r(ix)) - (2*S.rx(ix).^2./S.r(ix).^3) ) .* (K.j1*w.j1) ./ S.r(ix); 49 | Hxxj0 = -(tmom/(4*pi)) .* ( S.rx(ix)./S.r(ix) ).^2 .* (K.j0*w.j0) ./ S.r(ix); 50 | 51 | Hxx = Hxxj1 + Hxxj0; 52 | 53 | % free-space 54 | K0.j1 = ( exp(-lam.j1.*(Z.j1+H.j1)) ) .* (lam.j1) ; 55 | K0.j0 = ( exp(-lam.j0.*(Z.j0+H.j0)) ) .* (lam.j0).^2 ; 56 | 57 | H0xxj1 = -(tmom/(4*pi)) .* ( (1./S.r(ix)) - (2*S.rx(ix).^2./S.r(ix).^3) ) .* (K0.j1*w.j1) ./ S.r(ix); 58 | H0xxj0 = -(tmom/(4*pi)) .* ( S.rx(ix)./S.r(ix) ).^2 .* (K0.j0*w.j0) ./ S.r(ix); 59 | 60 | H0xx = H0xxj1 + H0xxj0; 61 | 62 | -------------------------------------------------------------------------------- /Code/calcHzz.m: -------------------------------------------------------------------------------- 1 | % Modified by Akbar 2 | function [Hzz,Hzz0] = calcHzz(ix,S,z,rTE,u0,lambda); 3 | %TZ-RZ 4 | % B. Minsley, March 2010 5 | 6 | %f(r) = int(K(lam)*Ji(lam*r)dlam 7 | %r*f(r) = sum(K(lam)*W) 8 | 9 | % decompose 10 | w = lambda.w(:); 11 | flen = lambda.flen; 12 | lam = lambda.lam(ix,:); 13 | 14 | % z is positive downwards 15 | h = -(z + S.tzoff(ix)); % transmitter height 16 | rz = z + S.rzoff(ix); % receiver elevation 17 | % Function that changed can be seen as text, Akbar 18 | 19 | %H = repmat(h,1,flen); 20 | H = h(:,ones(1,flen)); 21 | 22 | %Z = repmat(rz,1,flen); 23 | Z = rz(:,ones(1,flen)); 24 | 25 | 26 | % truncate 27 | u0 = u0(ix,:); 28 | rTE = rTE(ix,:); 29 | tmom = S.tmom(ix); 30 | 31 | 32 | % K(lam) - eqn. 4.46 33 | K = ( exp(-u0.*(Z+H)) + rTE .* exp(u0.*(Z-H)) ) .* (lam.^3) ./ u0; 34 | % K = ( exp(-u0.*(rzoff)) + rTE.* exp(u0.*(2*tz+rzoff)) ) .* lam(.^3) ./ u0; 35 | 36 | Hzz = (tmom/(4*pi)) .* (K*w) ./ S.r(ix); 37 | 38 | % free-space 39 | K0 = ( exp(-u0.*(Z+H)) ) .* (lam.^3) ./ u0; 40 | 41 | Hzz0 = (tmom/(4*pi)) .* (K0*w) ./ S.r(ix); -------------------------------------------------------------------------------- /Code/calcWTW.m: -------------------------------------------------------------------------------- 1 | function[ WTW] = calcWTW(dx,dz,dy,wt,alx,aly,alz,als) 2 | % [WTW] = calcWTW(MTX,wt) 3 | % Calculate WTW - the model regularization matrix 4 | % USE: grad, kron3 5 | 6 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 7 | % For more information, go to http://software.seg.org/2007/0001 . 8 | % You must read and accept usage terms at: 9 | % http://software.seg.org/disclaimer.txt before use. 10 | % 11 | % Revision history: 12 | % Original SEG version by Adam Pidlisecky and Eldad Haber 13 | % Last update, July 2005 14 | 15 | nx=length(dx); 16 | ny=length(dy); 17 | nz=length(dz); 18 | 19 | [Gx,Gz,Gy] = grad(dx,dy,dz); 20 | 21 | 22 | %%Create a weighted smallness term 23 | V = spdiags(mkvc(wt), 0, nx*ny*nz, nx*ny*nz); 24 | 25 | %Assemble the Anisotropic gradient operrator 26 | Gs = [alx*Gx;alz*Gz;aly*Gy]; 27 | 28 | %Weights certain points more than others 29 | Wt = spdiags(mkvc(wt),0,nx*ny*nz,nx*ny*nz); 30 | 31 | 32 | %assemble the 3d weighting matrix 33 | WTW = Wt' * ( Gs' * Gs + als * V) * Wt; 34 | 35 | -------------------------------------------------------------------------------- /Code/calcrTEsens.m: -------------------------------------------------------------------------------- 1 | function [varargout] = calcrTEsens(S,M,lam,flg) 2 | %% calculate reflection coefficient according to Ward and Hohmann, EM theory for geophysical applications 3 | % B. Minsley, June 2010 4 | 5 | % CITATION: 6 | % Minsley, B. J. (2011), A trans-dimensional Bayesian Markov chain Monte 7 | % algorithm for model assessment using frequency-domain electromagnetic data, 8 | % Geophysical Journal International, 187(1), 21, doi:10.1111/j.1365-246X.2011.05165.x. 9 | 10 | %% 11 | 12 | % constants 13 | eps0 = 1/(35950207149.4727056*pi);%8.8541878176e-12; 14 | mu0 = 4*pi*1e-7; 15 | 16 | flen = size(lam,2); 17 | 18 | % angular frequency 19 | omega = 2*pi*S.freq; 20 | nf = length(omega); 21 | 22 | %% add air layer onto top of model 23 | con = [0 M.con']; 24 | chie = [0 M.chie']; 25 | chim = [0 M.chim']; 26 | nlyr = length(con); 27 | h = [NaN;M.thk]; 28 | 29 | %% set impedivity, admitivity, wavenumber (zn,yn,un) 30 | % un = sqrt(kx^2 + ky^2 - kn^2) = sqrt(lam^2 - kn^2) 31 | % kn = sqrt(-zn*yn) = sqrt(omega^2*mu_n*eps_n - j*omega*mu_n*sigma_n) 32 | % zn = j*omega*mu_n, yn = j*omega*eps_n + sigma_n 33 | yn = 1j*omega*eps0*(1+chie) + con(ones(nf,1),:); 34 | yn = reshape(yn,nf,1,nlyr); 35 | zn = 1j*omega*mu0*(1+chim); 36 | zn = reshape(zn,nf,1,nlyr); 37 | 38 | % eqn 4.29 39 | lam_sq = lam.^2; 40 | un = sqrt( lam_sq(:,:,ones(1,1,nlyr)) + ... 41 | zn(:,ones(1,flen,1),:).*yn(:,ones(1, flen, 1),:) ); 42 | 43 | %% set layer admittances, Yn 44 | % eqn 4.27 45 | Yn = un ./ zn(:,ones(1, flen, 1),:); 46 | 47 | if flg == 0 48 | %% no sensitivity output 49 | % set half-space admittance derivative wrt log(sigma) 50 | % eqn 4.26 (Y is Yhat) 51 | Y(:,:,nlyr) = Yn(:,:,nlyr); 52 | Y(:,:,1) = NaN; % air layer 53 | 54 | % in case of a half-space 55 | if nlyr == 2 56 | rTE = (Yn(:,:,1) - Y(:,:,2)) ./ (Yn(:,:,1) + Y(:,:,2)); 57 | u0 = un(:,:,1); 58 | varargout = {rTE,u0}; 59 | return 60 | end 61 | 62 | %% iterate to find surface admittance & sensitivity 63 | for i = nlyr-1:-1:2 64 | tanuh = tanh(un(:,:,i)*h(i)); % store common operation 65 | 66 | % Y = Yhat for each layer 67 | num = Y(:,:,i+1) + Yn(:,:,i) .* tanuh; 68 | den = Yn(:,:,i) + Y(:,:,i+1) .* tanuh; 69 | Y(:,:,i) = Yn(:,:,i) .* num ./ den; 70 | end 71 | 72 | % outputs 73 | rTE = (Yn(:,:,1) - Y(:,:,2)) ./ (Yn(:,:,1) + Y(:,:,2)); 74 | u0 = un(:,:,1); 75 | 76 | varargout = {rTE,u0}; 77 | 78 | else 79 | %% initialize arrays for admittance & sensitivities 80 | % set half-space admittance derivative wrt log(sigma) 81 | % eqn 4.26 (Y is Yhat) 82 | Y(:,:,nlyr) = Yn(:,:,nlyr); 83 | Y(:,:,1) = NaN; % air layer 84 | dYdlogcon(:,:,nlyr) = con(end)./(2*un(:,:,end)); 85 | dYdlogcon(:,:,1) = NaN; % air layer 86 | dYdY = ones([size(lam) nlyr]); 87 | 88 | % in case of a half-space 89 | if nlyr == 2 90 | rTE = (Yn(:,:,1) - Y(:,:,2)) ./ (Yn(:,:,1) + Y(:,:,2)); 91 | u0 = un(:,:,1); 92 | drTEdlogcon = -2*Yn(:,:,1).*dYdlogcon(:,:,nlyr)./(Yn(:,:,1) + Y(:,:,2)).^2; 93 | varargout = {rTE,u0,drTEdlogcon}; 94 | return 95 | end 96 | 97 | %% iterate to find surface admittance & sensitivity 98 | for i = nlyr-1:-1:2 99 | tanuh = tanh(un(:,:,i)*h(i)); % store common operation 100 | 101 | % Y = Yhat for each layer 102 | num = Y(:,:,i+1) + Yn(:,:,i) .* tanuh; 103 | den = Yn(:,:,i) + Y(:,:,i+1) .* tanuh; 104 | Y(:,:,i) = Yn(:,:,i) .* num ./ den; 105 | 106 | % dY(i) / d(ln con(i)) 107 | dYdlogcon(:,:,i) = (con(i)./(2*un(:,:,i).*den.^2)) .* (... 108 | 2*Yn(:,:,i) .* Y(:,:,i+1) .* tanuh.^2 + ... 109 | (1j*omega(:,ones(1,flen))*mu0*(1+chim(i))*h(i)) .* (Yn(:,:,i).*Y(:,:,i+1).^2 - Yn(:,:,i).^3) .* tanuh.^2 + ... 110 | (Y(:,:,i+1).^2 - Yn(:,:,i).^2) .* tanuh + 2*Yn(:,:,i).^2 + ... 111 | (1j*omega(:,ones(1,flen))*mu0*(1+chim(i))*h(i)) .* (Yn(:,:,i).^3 - Yn(:,:,i).*Y(:,:,i+1).^2) ); 112 | 113 | % dY(i) / dY(i+1) 114 | numYY = Yn(:,:,i).^2 .* (1 - tanuh.^2); 115 | denYY = ( Yn(:,:,i) + Y(:,:,i+1) .* tanuh ).^2; 116 | dYdY(:,:,i+1) = numYY ./ denYY; 117 | 118 | end 119 | dYdlogcon(:,:,1) = []; %air layer 120 | dYdY(:,:,1) = []; %air layer 121 | 122 | % outputs 123 | rTE = (Yn(:,:,1) - Y(:,:,2)) ./ (Yn(:,:,1) + Y(:,:,2)); 124 | u0 = un(:,:,1); 125 | 126 | num = -2 * repmat(Yn(:,:,1),[1 1 nlyr-1]); 127 | den = repmat( (Yn(:,:,1) + Y(:,:,2)) .^2 , [1 1 nlyr-1] ); 128 | 129 | drTEdlogcon = num .* (cumprod(dYdY,3) .* dYdlogcon) ./ den; 130 | 131 | varargout = {rTE,u0,drTEdlogcon}; 132 | end 133 | 134 | -------------------------------------------------------------------------------- /Code/cubicSpline.m: -------------------------------------------------------------------------------- 1 | function varargout = cubicSpline(coeff,smoothness); 2 | % NATURAL CUBIC SPLINE ALGORITHM 3.4 3 | % from Book: Numerical Analysis 6th edition by Richard L. Burden and 4 | % J Douglas Faires; Published by Brooks/Cole Publishing Company 5 | % 6 | % To construct the cubic spline interpolant S for the function f, 7 | % defined at the numbers x(0) < x(1) < ... < x(n), satisfying 8 | % S''(x(0)) = S''(x(n)) = 0: 9 | % 10 | % INPUT: A matrix with two columns and n rows (nx2) where column 1 11 | % is the X data and column 2 is f(X) or Y values. [Xo,Yo] 12 | % [X1,Y1] 13 | % [: : ] 14 | % [Xn,Yn] 15 | % 16 | % OUTPUT: The new X and Y coordinates of the smoothed curve ready to plot. 17 | % 18 | % NOTE: S(x) = A(J) + B(J)*( x - x(J) ) + C(J)*( x - x(J) )**2 + 19 | % D(J) * ( x - x(J) )**3 for x(J) <= x < x(J + 1) 20 | % 21 | % NOTE: A smoothness factor of 32 works well. This spline technique 22 | % gives a more accurate curve than the built in Matlab Spline 23 | % function. In that it comes very close to the original data 24 | % points. 25 | 26 | N = size(coeff,1)-1; 27 | 28 | if N > 0 29 | X = zeros(1,N+1); 30 | A = zeros(1,N+1); 31 | for I = 0:N 32 | X(I+1) = coeff(I+1,1); 33 | A(I+1) = coeff(I+1,2); 34 | end 35 | end 36 | 37 | M = N - 1; 38 | % STEP 1 39 | H = zeros(1,M+1); 40 | for I = 0:M 41 | H(I+1) = X(I+2) - X(I+1); 42 | end 43 | 44 | % STEP 2 45 | % Use XA in place of ALPHA 46 | XA = zeros(1,M+1); 47 | for I = 1:M 48 | XA(I+1) = 3.0*(A(I+2)*H(I)-A(I+1)*(X(I+2)-X(I))+A(I)*H(I+1))/(H(I+1)*H(I)); 49 | end 50 | 51 | % STEP 3 52 | % STEPs 3, 4, 5 and part of 6 solve the tridiagonal system using 53 | % Crout reduction. 54 | % use XL, XU, XZ in place of L, MU, Z resp. 55 | XL = zeros(1,N+1); 56 | XU = zeros(1,N+1); 57 | XZ = zeros(1,N+1); 58 | XL(1) = 1; 59 | XU(1) = 0; 60 | XZ(1) = 0; 61 | 62 | % STEP 4 63 | for I = 1:M 64 | XL(I+1) = 2*(X(I+2)-X(I))-H(I)*XU(I); 65 | XU(I+1) = H(I+1)/XL(I+1); 66 | XZ(I+1) = (XA(I+1)-H(I)*XZ(I))/XL(I+1); 67 | end 68 | 69 | % STEP 5 70 | XL(N+1) = 1; 71 | XZ(N+1) = 0; 72 | B = zeros(1,N+1); 73 | C = zeros(1,N+1); 74 | D = zeros(1,N+1); 75 | C(N+1) = XZ(N+1); 76 | 77 | % STEP 6 78 | for I = 0:M 79 | J = M-I; 80 | C(J+1) = XZ(J+1)-XU(J+1)*C(J+2); 81 | B(J+1) = (A(J+2)-A(J+1))/H(J+1) - H(J+1) * (C(J+2) + 2.0 * C(J+1)) / 3.0; 82 | D(J+1) = (C(J+2) - C(J+1)) / (3.0 * H(J+1)); 83 | end 84 | 85 | % Use the above data A, B, C, and D, along with x to calculate the ySpline points. 86 | xSpline = []; 87 | xpoints = cell(1); 88 | for i=1:length(X)-1 89 | xpoints{i} = X(i):(X(i+1)-X(i))/smoothness:X(i+1); 90 | xSpline = cat(2,xSpline,xpoints{i}); 91 | end 92 | 93 | xSpline = unique(xSpline); 94 | ySplineIdx = 1; 95 | for i=1:length(xpoints) 96 | for j=1:smoothness 97 | xCalc = xpoints{i}(j)-xpoints{i}(1); 98 | ySpline(ySplineIdx) = A(i) + B(i)*(xCalc) + C(i)*power(xCalc,2) + D(i)*power(xCalc,3); 99 | ySplineIdx=ySplineIdx+1; 100 | end 101 | end 102 | ySpline(end+1) = coeff(end,2); % add in the final y data point from the original data. 103 | 104 | varargout{1} = xSpline; 105 | varargout{2} = ySpline; -------------------------------------------------------------------------------- /Code/fdem1dfwd.m: -------------------------------------------------------------------------------- 1 | function [prd, varargout] = fdem1dfwd(S,M,el,flg) 2 | % given a system, model, and coordinates, predict data 3 | % optionally output sensitivities if flg = 1; 4 | % B. Minsley, June 2010 5 | 6 | % CITATION: 7 | % Minsley, B. J. (2011), A trans-dimensional Bayesian Markov chain Monte 8 | % algorithm for model assessment using frequency-domain electromagnetic data, 9 | % Geophysical Journal International, 187(1), 21, doi:10.1111/j.1365-246X.2011.05165.x. 10 | 11 | % *** changed C.el to el, May 2012 12 | 13 | %% set lambda values as global variable (once per system configuration) 14 | persistent lambda 15 | if isempty(lambda) 16 | lambda = getLambda(S.r,'long','long'); 17 | end 18 | M.con=10.^M.con; 19 | %% switch for coil orientations 20 | zz = find(strcmp(S.tor,'z') & strcmp(S.ror,'z')); %HCP 21 | yy = find(strcmp(S.tor,'y') & strcmp(S.ror,'y')); %VCP 22 | xx = find(strcmp(S.tor,'x') & strcmp(S.ror,'x')); %VCX 23 | 24 | yz = find(strcmp(S.tor,'z') & strcmp(S.ror,'y')); %TZ-RY 25 | xz = find(strcmp(S.tor,'z') & strcmp(S.ror,'x')); %TZ-RX 26 | 27 | zx = find(strcmp(S.tor,'x') & strcmp(S.ror,'z')); %TX-RZ 28 | yx = find(strcmp(S.tor,'x') & strcmp(S.ror,'y')); %TX-RY 29 | 30 | zy = find(strcmp(S.tor,'y') & strcmp(S.ror,'z')); %TY-RZ 31 | xy = find(strcmp(S.tor,'y') & strcmp(S.ror,'x')); %TY-RX 32 | 33 | if flg == 0 %% no sensitivity output 34 | %% calculate reflection coefficient 35 | %tic 36 | if ~isempty(zz) || ~isempty(xx)|| ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 37 | [rTE.j0,u0.j0] = calcrTEsens(S,M,lambda.j0.lam,flg); 38 | end 39 | if ~isempty(zx) || ~isempty(zy) || ~isempty(xz) || ~isempty(yz) || ~isempty(xx) ... 40 | || ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 41 | [rTE.j1,u0.j1] = calcrTEsens(S,M,lambda.j1.lam,flg); 42 | end 43 | %a=toc 44 | 45 | %% calculate H & H0 for all orientations 46 | % z-oriented transmitter 47 | %tic 48 | if ~isempty(zz) %HCP 49 | [H(zz),H0(zz)] = calcHzz(zz,S,el,rTE.j0,u0.j0,lambda.j0); 50 | end 51 | if ~isempty(xx) %VCX 52 | [H(xx),H0(xx)] = calcHxx(xx,S,el,rTE,u0,lambda); 53 | end 54 | %b=toc 55 | %[a/(a+b) b/(a+b)] 56 | % if ~isempty(yz) 57 | % H0(yz) = calcHyz(yz,S,1e3*C.z(1),rTE.j1,u0.j1,lambda.j1); 58 | % H(yz) = calcHyz(yz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 59 | % end 60 | % if ~isempty(xz) 61 | % H0(xz) = calcHxz(xz,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 62 | % H(xz) = calcHxz(xz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 63 | % end 64 | % 65 | % % x-oriented transmitter 66 | % if ~isempty(zx) 67 | % H0(zx) = calcHzx(zx,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 68 | % H(zx) = calcHzx(zx,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 69 | % end 70 | 71 | % scaling factor for moments- need to fix this... 72 | scl = S.tmom .* S.rmom; 73 | 74 | prd(:,1) = 1e6*(H - H0)./H0; 75 | prd = prd.*scl; 76 | 77 | varargout = {}; 78 | 79 | elseif flg == 1 %% output sensitivities 80 | %% calculate reflection coefficient 81 | if ~isempty(zz) || ~isempty(xx)|| ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 82 | [rTE.j0,u0.j0,drTEdlogcon.j0] = calcrTEsens(S,M,lambda.j0.lam,flg); 83 | end 84 | if ~isempty(zx) || ~isempty(zy) || ~isempty(xz) || ~isempty(yz) || ~isempty(xx) ... 85 | || ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 86 | [rTE.j1,u0.j1,drTEdlogcon.j1] = calcrTEsens(S,M,lambda.j1.lam,flg); 87 | end 88 | 89 | %% calculate H & H0 for all orientations plus sensitivities 90 | 91 | 92 | for i = 1:length(M.con) % loop over layers 93 | 94 | if ~isempty(zz) %HCP 95 | if i==1,[H(zz),H0(zz)] = calcHzz(zz,S,el,rTE.j0,u0.j0,lambda.j0);end 96 | [dH(zz,i),dH0(zz,i)] = calcHzz(zz,S,el,drTEdlogcon.j0(:,:,i),u0.j0,lambda.j0); 97 | end 98 | if ~isempty(xx) %VCX 99 | if i==1,[H(xx),H0(xx)] = calcHxx(xx,S,el,rTE,u0,lambda);end 100 | drTE.j0 = drTEdlogcon.j0(:,:,i); 101 | drTE.j1 = drTEdlogcon.j1(:,:,i); 102 | [dH(xx,i),dH0(xx,i)] = calcHxx(xx,S,el,drTE,u0,lambda); 103 | end 104 | % if ~isempty(yz) 105 | % H0(yz) = calcHyz(yz,S,1e3*C.z(1),rTE.j1,u0.j1,lambda.j1); 106 | % H(yz) = calcHyz(yz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 107 | % end 108 | % if ~isempty(xz) 109 | % H0(xz) = calcHxz(xz,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 110 | % H(xz) = calcHxz(xz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 111 | % end 112 | % 113 | % % x-oriented transmitter 114 | % if ~isempty(zx) 115 | % H0(zx) = calcHzx(zx,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 116 | % H(zx) = calcHzx(zx,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 117 | % end 118 | 119 | 120 | end 121 | 122 | % scaling factor for moments- need to fix this... 123 | scl = S.tmom .* S.rmom; 124 | 125 | prd(:,1) = 1e6*(H - H0)./H0; 126 | prd = prd.*scl; 127 | J = 1e6*(dH - dH0)./dH0; 128 | 129 | % Changed code here: ,Akbar 130 | %J = J.*repmat(scl,1,size(J,2)); 131 | J = J.* scl(:,ones(1,size(J,2))); 132 | 133 | varargout = {J}; 134 | 135 | end -------------------------------------------------------------------------------- /Code/fdem1dfwd2.m: -------------------------------------------------------------------------------- 1 | function [prd, varargout] = fdem1dfwd2(aq,S,M,el,flg) 2 | % given a system, model, and coordinates, predict data 3 | % optionally output sensitivities if flg = 1; 4 | % B. Minsley, June 2010 5 | 6 | % CITATION: 7 | % Minsley, B. J. (2011), A trans-dimensional Bayesian Markov chain Monte 8 | % algorithm for model assessment using frequency-domain electromagnetic data, 9 | % Geophysical Journal International, 187(1), 21, doi:10.1111/j.1365-246X.2011.05165.x. 10 | 11 | % *** changed C.el to el, May 2012 12 | 13 | %% set lambda values as global variable (once per system configuration) 14 | M.con=aq; 15 | persistent lambda 16 | if isempty(lambda) 17 | lambda = getLambda(S.r,'long','long'); 18 | end 19 | M.con=10.^M.con; 20 | %% switch for coil orientations 21 | zz = find(strcmp(S.tor,'z') & strcmp(S.ror,'z')); %HCP 22 | yy = find(strcmp(S.tor,'y') & strcmp(S.ror,'y')); %VCP 23 | xx = find(strcmp(S.tor,'x') & strcmp(S.ror,'x')); %VCX 24 | 25 | yz = find(strcmp(S.tor,'z') & strcmp(S.ror,'y')); %TZ-RY 26 | xz = find(strcmp(S.tor,'z') & strcmp(S.ror,'x')); %TZ-RX 27 | 28 | zx = find(strcmp(S.tor,'x') & strcmp(S.ror,'z')); %TX-RZ 29 | yx = find(strcmp(S.tor,'x') & strcmp(S.ror,'y')); %TX-RY 30 | 31 | zy = find(strcmp(S.tor,'y') & strcmp(S.ror,'z')); %TY-RZ 32 | xy = find(strcmp(S.tor,'y') & strcmp(S.ror,'x')); %TY-RX 33 | 34 | if flg == 0 %% no sensitivity output 35 | %% calculate reflection coefficient 36 | %tic 37 | if ~isempty(zz) || ~isempty(xx)|| ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 38 | [rTE.j0,u0.j0] = calcrTEsens(S,M,lambda.j0.lam,flg); 39 | end 40 | if ~isempty(zx) || ~isempty(zy) || ~isempty(xz) || ~isempty(yz) || ~isempty(xx) ... 41 | || ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 42 | [rTE.j1,u0.j1] = calcrTEsens(S,M,lambda.j1.lam,flg); 43 | end 44 | %a=toc 45 | 46 | %% calculate H & H0 for all orientations 47 | % z-oriented transmitter 48 | %tic 49 | if ~isempty(zz) %HCP 50 | [H(zz),H0(zz)] = calcHzz(zz,S,el,rTE.j0,u0.j0,lambda.j0); 51 | end 52 | if ~isempty(xx) %VCX 53 | [H(xx),H0(xx)] = calcHxx(xx,S,el,rTE,u0,lambda); 54 | end 55 | %b=toc 56 | %[a/(a+b) b/(a+b)] 57 | % if ~isempty(yz) 58 | % H0(yz) = calcHyz(yz,S,1e3*C.z(1),rTE.j1,u0.j1,lambda.j1); 59 | % H(yz) = calcHyz(yz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 60 | % end 61 | % if ~isempty(xz) 62 | % H0(xz) = calcHxz(xz,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 63 | % H(xz) = calcHxz(xz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 64 | % end 65 | % 66 | % % x-oriented transmitter 67 | % if ~isempty(zx) 68 | % H0(zx) = calcHzx(zx,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 69 | % H(zx) = calcHzx(zx,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 70 | % end 71 | 72 | % scaling factor for moments- need to fix this... 73 | scl = S.tmom .* S.rmom; 74 | 75 | prd(:,1) = 1e6*(H - H0)./H0; 76 | prd = prd.*scl; 77 | 78 | varargout = {}; 79 | 80 | elseif flg == 1 %% output sensitivities 81 | %% calculate reflection coefficient 82 | if ~isempty(zz) || ~isempty(xx)|| ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 83 | [rTE.j0,u0.j0,drTEdlogcon.j0] = calcrTEsens(S,M,lambda.j0.lam,flg); 84 | end 85 | if ~isempty(zx) || ~isempty(zy) || ~isempty(xz) || ~isempty(yz) || ~isempty(xx) ... 86 | || ~isempty(yy) || ~isempty(xy) || ~isempty(yx) 87 | [rTE.j1,u0.j1,drTEdlogcon.j1] = calcrTEsens(S,M,lambda.j1.lam,flg); 88 | end 89 | 90 | %% calculate H & H0 for all orientations plus sensitivities 91 | 92 | 93 | for i = 1:length(M.con) % loop over layers 94 | 95 | if ~isempty(zz) %HCP 96 | if i==1,[H(zz),H0(zz)] = calcHzz(zz,S,el,rTE.j0,u0.j0,lambda.j0);end 97 | [dH(zz,i),dH0(zz,i)] = calcHzz(zz,S,el,drTEdlogcon.j0(:,:,i),u0.j0,lambda.j0); 98 | end 99 | if ~isempty(xx) %VCX 100 | if i==1,[H(xx),H0(xx)] = calcHxx(xx,S,el,rTE,u0,lambda);end 101 | drTE.j0 = drTEdlogcon.j0(:,:,i); 102 | drTE.j1 = drTEdlogcon.j1(:,:,i); 103 | [dH(xx,i),dH0(xx,i)] = calcHxx(xx,S,el,drTE,u0,lambda); 104 | end 105 | % if ~isempty(yz) 106 | % H0(yz) = calcHyz(yz,S,1e3*C.z(1),rTE.j1,u0.j1,lambda.j1); 107 | % H(yz) = calcHyz(yz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 108 | % end 109 | % if ~isempty(xz) 110 | % H0(xz) = calcHxz(xz,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 111 | % H(xz) = calcHxz(xz,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 112 | % end 113 | % 114 | % % x-oriented transmitter 115 | % if ~isempty(zx) 116 | % H0(zx) = calcHzx(zx,S,1e6*C.z(1),rTE.j1,u0.j1,lambda.j1); 117 | % H(zx) = calcHzx(zx,S,C.z(1),rTE.j1,u0.j1,lambda.j1); 118 | % end 119 | 120 | 121 | end 122 | 123 | % scaling factor for moments- need to fix this... 124 | scl = S.tmom .* S.rmom; 125 | 126 | prd(:,1) = 1e6*(H - H0)./H0; 127 | prd = prd.*scl; 128 | J = 1e6*(dH - dH0)./dH0; 129 | 130 | % Changed code here: ,Akbar 131 | %J = J.*repmat(scl,1,size(J,2)); 132 | J = J.* scl(:,ones(1,size(J,2))); 133 | 134 | varargout = {J}; 135 | 136 | end -------------------------------------------------------------------------------- /Code/fdemCal.m: -------------------------------------------------------------------------------- 1 | %input should be # cal points x # frequencies 2 | load GEMCalWorkspace 3 | 4 | x=calX; % x coordinate for co-located GEM & DC 5 | dcal = prdGEM; % data you are calibrating to (predicted response to the DC model) 6 | dobs = obsGEM; % data you want to calibrate (the observed GEM) 7 | 8 | ns = size(dobs,1); % soundings 9 | nf = size(dobs,2); % frequencies 10 | 11 | % initial values 12 | G = ones(1,nf); % gain 13 | B = zeros(1,nf); % bias 14 | dprd = (dcal + repmat(B,ns,1))*diag(G); 15 | 16 | % weights - leave at ones for now... it works, but should be fixed 17 | wd = ones(1,nf); % enter 1/sigma values 18 | wm = [1 1]; % G, B 19 | 20 | % build block matrices - kind of klugey for now... 21 | for i=1:nf 22 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 23 | A(i).D = dobs(:,i) - dprd(:,i); 24 | A(i).Wd = wd(i)*eye(ns); 25 | A(i).Wm = diag(wm); 26 | A(i).m = [G(i);B(i)]; 27 | end 28 | J = blkdiag(A.J); 29 | D = blkdiag(A.D); 30 | Wd = blkdiag(A.Wd); 31 | Wm = blkdiag(A.Wm); 32 | m = blkdiag(A.m); 33 | m0 = blkdiag(A.m); 34 | 35 | 36 | %% solve 37 | for n = 1:10 38 | 39 | H = J'*Wd'*Wd*J + Wm'*Wm; 40 | r = J'*Wd'*D + Wm'*Wm*(m-m0); 41 | 42 | % calculate update 43 | dm = H\r; 44 | m = m + dm; 45 | G = G + diag(dm(1:2:end,:)).'; 46 | B = B + diag(dm(2:2:end,:)).'; 47 | 48 | % update predicted & calibrated data 49 | dprd = (dcal + repmat(B,ns,1))*diag(G); 50 | dcor = dobs*diag(1./G) - repmat(B,ns,1); 51 | 52 | % update block matrices - kind of klugey for now... 53 | for i=1:nf 54 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 55 | A(i).D = dobs(:,i) - dprd(:,i); 56 | end 57 | J = blkdiag(A.J); 58 | D = blkdiag(A.D); 59 | 60 | % misfit 61 | err(n,:) = diag(D'*(Wd'*Wd)*D); 62 | 63 | end 64 | 65 | %% PCA filter 66 | m = mean(dcor.',2); 67 | M = repmat(m,1,ns); 68 | [u,s,v] = svd(dcor.' - M); 69 | lp = u(:,1)*u(:,1)'*(dcor.'-M) + M; % 1st component only 70 | 71 | %% Display 72 | for i = 1:nf 73 | figure 74 | subplot(2,3,[1 2]);hold on; 75 | ylabel('ppm');title(['I - ' num2str(f(i))]); 76 | plot(x,real(dobs(:,i)),'b.-') 77 | %plot(flipud(gemXfilt),real(filtGEMobs(:,i)),'g.-') 78 | plot(x,real(dcal(:,i)),'r.-') 79 | plot(x,real(dcor(:,i)),'m.-') 80 | plot(x,real(lp(i,:)),'c.-') 81 | legend({'observed GEM','prd GEM from DC','calibrated GEM','calibrated & filtered GEM'}) 82 | xlim([0 max(x)]) 83 | subplot(2,3,[4 5]);hold on; 84 | xlabel('distance (m)');ylabel('ppm');title(['Q - ' num2str(f(i))]); 85 | plot(x,imag(dobs(:,i)),'b.-') 86 | plot(x,imag(dcal(:,i)),'r.-') 87 | plot(x,imag(dcor(:,i)),'m.-') 88 | plot(x,imag(lp(i,:)),'c.-') 89 | xlim([0 max(x)]) 90 | subplot(2,3,3);hold on 91 | plot(angle(dobs(:,i))*180/pi,abs(dobs(:,i)),'b.') 92 | % plot(angle(filtGEMobs(:,i))*180/pi,abs(filtGEMobs(:,i)),'g.') 93 | plot(angle(dcal(:,i))*180/pi,abs(dcal(:,i)),'r.') 94 | plot(angle(dcor(:,i))*180/pi,abs(dcor(:,i)),'m.') 95 | plot(angle(lp(i,:))*180/pi,abs(lp(i,:)),'c.') 96 | xlabel('phase');ylabel('amplitude') 97 | title(['G = ' num2str(abs(G(i))) ', \phi = ' num2str(angle(G(i))*180/pi) ', B = ' num2str(B(i))]); 98 | subplot(2,3,6);hold on 99 | plot(dobs(:,i),'b.') 100 | %plot(filtGEMobs(:,i),'g.') 101 | plot(dcal(:,i),'r.') 102 | plot(dcor(:,i),'m.') 103 | plot(lp(i,:),'c.') 104 | xlabel('in phase');ylabel('quadrature') 105 | %title(['G_p_c_a = ' num2str(abs(G(i))) ', \phi_p_c_a = ' num2str(angle(G(i))*180/pi) ', B_p_c_a = ' num2str(B(i))]) 106 | end 107 | 108 | 109 | -------------------------------------------------------------------------------- /Code/file: -------------------------------------------------------------------------------- 1 | file 2 | -------------------------------------------------------------------------------- /Code/getLambda.m: -------------------------------------------------------------------------------- 1 | function lambda = getLambda(r,j0len,j1len) 2 | %% load Guptasarma1997 filters - make sure digFilt/ is in the path! 3 | % B. Minsley, March 2010 4 | 5 | %% JO 6 | if (strcmp(j0len,'long')) 7 | load J0_120pt.mat; 8 | flen = 120; 9 | else 10 | load J0_61pt.mat; 11 | flen = 61; 12 | end 13 | 14 | lambda.j0.a = a; 15 | lambda.j0.s = s; 16 | lambda.j0.w = w; 17 | lambda.j0.flen = flen; 18 | 19 | % make lambda for all coil spacings: Guptasarma1997, eqn2. 20 | % lambda is size #coil-spacings (rows) by filter length (cols) 21 | i = 1:flen; 22 | l1 = 1./r; 23 | l2 = 10.^(a+(i-1)*s); 24 | lambda.j0.lam = l1 * l2; 25 | 26 | %% J1 27 | if (strcmp(j1len,'long')) 28 | load J1_140pt.mat; 29 | flen = 140; 30 | else 31 | load J1_47pt.mat; 32 | flen = 47; 33 | end 34 | 35 | lambda.j1.a = a; 36 | lambda.j1.s = s; 37 | lambda.j1.w = w; 38 | lambda.j1.flen = flen; 39 | 40 | 41 | % make lambda for all coil spacings: Guptasarma1997, eqn2. 42 | % lambda is size #coil-spacings (rows) by filter length (cols) 43 | i = 1:flen; 44 | l1 = 1./r; 45 | l2 = 10.^(a+(i-1)*s); 46 | lambda.j1.lam = l1 * l2; 47 | -------------------------------------------------------------------------------- /Code/getcontourlines.m: -------------------------------------------------------------------------------- 1 | function s = getcontourlines(c) 2 | 3 | sz = size(c,2); 4 | ii = 1; 5 | jj = 1; 6 | 7 | while ii < sz 8 | n = c(2,ii); 9 | s(jj).v = c(1,ii); 10 | s(jj).x = c(1,ii+1:ii+n); 11 | s(jj).y = c(2,ii+1:ii+n); 12 | ii = ii + n + 1; 13 | jj = jj + 1; 14 | end 15 | 16 | end -------------------------------------------------------------------------------- /Code/grad.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/grad.m -------------------------------------------------------------------------------- /Code/grad2d.m: -------------------------------------------------------------------------------- 1 | function[Gx,Gz] = grad2d(dx,dz) 2 | % [G,Gx,Gz] = grad2d(dx,dz) 3 | %% dx is the x direction cell discretization, a vector length [nx,1]; 4 | %% dz is the z direction cell discretization, a vector length [nz,1]; 5 | %Adam Pidlisecky 2005; based on an implementation of E.Haber 1999 for the 6 | %3D problem 7 | 8 | dx = shiftdim(dx); 9 | dz = shiftdim(dz); 10 | 11 | Nx = length(dx)-2; 12 | Nz = length(dz)-2; 13 | 14 | % Number the phi grid 15 | np = (Nx+2)*(Nz+2); 16 | GRDp = reshape(1:1:np,Nx+2,Nz+2); 17 | 18 | % Number the Ax grid 19 | nax = (Nx+1)*(Nz+2); 20 | GRDax = reshape(1:1:nax, (Nx+1),(Nz+2)); 21 | 22 | % Number the Az grid 23 | naz = (Nx+2)*(Nz+1); 24 | GRDaz = reshape(1:1:naz, (Nx+2),(Nz+1)); 25 | 26 | %%%% Generate d/dx %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27 | 28 | lx = []; jx = []; kx = []; 29 | 30 | % Generate grid 31 | ex = ones(Nx+2,1); 32 | ez = ones(Nz+2,1); 33 | Dx =kron(dx',ez)'; 34 | % Entries (l,j,k) 35 | 36 | lx = mkvc(GRDax); 37 | jx = mkvc(GRDp(1:end-1,:)); 38 | kx = mkvc(-2./(Dx(1:end-1,:) + Dx(2:end,:))); 39 | 40 | % Entries (l+1,j,k) 41 | 42 | lx = [lx; lx]; 43 | jx = [jx;mkvc(GRDp(2:end,:))]; 44 | kx = [kx;-kx]; 45 | 46 | 47 | %%%% Generate d/dz %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 48 | 49 | lz = []; jz = []; kz = []; 50 | Dz = kron(ex',dz)'; 51 | % Entries (l,j,k) 52 | 53 | lz = mkvc(GRDaz); 54 | jz = mkvc(GRDp(:,1:end-1)); 55 | kz = mkvc(-2./(Dz(:,1:end-1) + Dz(:,2:end)));; 56 | 57 | % Entries (l,j,k+1) 58 | 59 | lz = [lz; lz]; 60 | jz = [jz;mkvc(GRDp(:,2:end))]; 61 | kz = [kz; -kz]; 62 | 63 | Gx = sparse(lx,jx,kx,nax,np); 64 | Gz = sparse(lz,jz,kz,naz,np); 65 | 66 | G = [Gx;Gz]; 67 | 68 | -------------------------------------------------------------------------------- /Code/grad3D.m: -------------------------------------------------------------------------------- 1 | function[Gx,Gy,Gz] = grad(dx,dy,dz) 2 | % [G] = grad(dx,dy,dz) 3 | %Creates the 3D finite volume gradient operator 4 | %operator is set up to handle variable grid discretization 5 | %dx,dy,dz are vectors containing the cell widths in the x y and z 6 | %directions, respectively 7 | % 8 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 9 | % For more information, go to http://software.seg.org/2007/0001 . 10 | % You must read and accept usage terms at: 11 | % http://software.seg.org/disclaimer.txt before use. 12 | % 13 | % Revision history: 14 | % Original SEG version by Adam Pidlisecky and Eldad Haber 15 | % Last update, July 2006 16 | 17 | dx = shiftdim(dx); 18 | dy = shiftdim(dy); 19 | dz = shiftdim(dz); 20 | 21 | Nx = length(dx)-2; 22 | Ny = length(dy)-2; 23 | Nz = length(dz)-2; 24 | 25 | %dx = [dx(1);dx;dx(end)]; 26 | %dy = [dy(1);dy;dy(end)]; 27 | %dz = [dz(1);dz;dz(end)]; 28 | 29 | 30 | % Number the phi grid 31 | np = (Nx+2)*(Ny+2)*(Nz+2); 32 | GRDp = reshape(1:1:np,Nx+2,Ny+2,Nz+2); 33 | 34 | 35 | % Number the Ax grid 36 | nax = (Nx+1)*(Ny+2)*(Nz+2); 37 | GRDax = reshape(1:1:nax, (Nx+1),(Ny+2),(Nz+2)); 38 | 39 | % Number the Ay grid 40 | nay = (Nx+2)*(Ny+1)*(Nz+2); 41 | GRDay = reshape(1:1:nay, (Nx+2),(Ny+1),(Nz+2)); 42 | 43 | % Number the Az grid 44 | naz = (Nx+2)*(Ny+2)*(Nz+1); 45 | GRDaz = reshape(1:1:naz, (Nx+2),(Ny+2),(Nz+1)); 46 | 47 | 48 | %%%% Generate d/dx %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 49 | 50 | lx = []; jx = []; kx = []; 51 | 52 | % Generate grid 53 | ex = ones(Nx+2,1); 54 | ey = ones(Ny+2,1); 55 | ez = ones(Nz+2,1); 56 | 57 | Dx = kron3(dx,ey,ez); 58 | % Entries (l,j,k) 59 | 60 | lx = mkvc(GRDax); 61 | jx = mkvc(GRDp(1:end-1,:,:)); 62 | kx = mkvc(-2./(Dx(1:end-1,:,:) + Dx(2:end,:,:))); 63 | 64 | % Entries (l+1,j,k) 65 | 66 | lx = [lx; lx]; 67 | jx = [jx;mkvc(GRDp(2:end,:,:))]; 68 | kx = [kx;-kx]; 69 | 70 | 71 | %%%% Generate d/dy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 72 | 73 | ly = []; jy = []; ky = []; 74 | 75 | Dy = kron3(ex,dy,ez); 76 | 77 | % Entries (l,j,k) 78 | 79 | ly = mkvc(GRDay); 80 | jy = mkvc(GRDp(:,1:end-1,:)); 81 | ky = mkvc(-2./(Dy(:,1:end-1,:) + Dy(:,2:end,:))); 82 | 83 | % Entries (l,j+1,k) 84 | 85 | ly = [ly; ly]; 86 | jy = [jy;mkvc(GRDp(:,2:end,:))]; 87 | ky = [ky;-ky]; 88 | 89 | 90 | %%%% Generate d/dz %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 91 | 92 | lz = []; jz = []; kz = []; 93 | 94 | Dz = kron3(ex,ey,dz); 95 | 96 | % Entries (l,j,k) 97 | 98 | lz = mkvc(GRDaz); 99 | jz = mkvc(GRDp(:,:,1:end-1)); 100 | kz = mkvc(-2./(Dz(:,:,1:end-1) + Dz(:,:,2:end)));; 101 | 102 | % Entries (l,j,k+1) 103 | 104 | lz = [lz; lz]; 105 | jz = [jz;mkvc(GRDp(:,:,2:end))]; 106 | kz = [kz; -kz]; 107 | 108 | Gx = sparse(lx,jx,kx,nax,np); 109 | Gy = sparse(ly,jy,ky,nay,np); 110 | Gz = sparse(lz,jz,kz,naz,np); 111 | 112 | 113 | G = [Gx;Gy;Gz]; 114 | 115 | -------------------------------------------------------------------------------- /Code/init.dat: -------------------------------------------------------------------------------- 1 | -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2 2 | -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2 3 | -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2 4 | -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2 5 | -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2 6 | -------------------------------------------------------------------------------- /Code/ipcg.m: -------------------------------------------------------------------------------- 1 | function [x,numiter,res] = ipcg(MTX, regpar, b, tol, intol, max_it,J,W) 2 | % [x,numiter] = ipcg(MTX, REGPAR, b, tol, k) 3 | % 4 | % Preconditioned CG for the system 5 | % (J'*J + regpar*L)x = r 6 | % where J*v is computed indirectly J*v = -Q*(A^{-1}*(G*v)) 7 | % 8 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 9 | % For more information, go to http://software.seg.org/2007/0001 . 10 | % You must read and accept usage terms at: 11 | % http://software.seg.org/disclaimer.txt before use. 12 | % 13 | % Revision history: 14 | % Original SEG version by Adam Pidlisecky and Eldad Haber 15 | % Last update, July 2006 16 | 17 | disp(' PCG -----'); 18 | 19 | %initialize starting variables 20 | r = b; 21 | n = length(b); 22 | x = zeros(n,1); 23 | rho = r'*r; 24 | 25 | if ( rho == 0.0 ), rho = 1.0; end 26 | 27 | err = norm( r ) / sqrt(rho); 28 | if ( err < tol ) disp('err < tol'); return, end 29 | 30 | for iter = 1:max_it % begin iteration 31 | 32 | % preconditioning step %%%%%% 33 | 34 | 35 | z = matsol(0.1*speye(n) + regpar*MTX.WTW, r, 1e-6); 36 | 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | rho_1 = rho; 39 | rho = (r'*z); 40 | if iter == 1, rho0 = norm(z); end; 41 | 42 | if ( iter > 1 ), % compute the direction vector 43 | beta = rho / rho_1; 44 | p = z + beta*p; 45 | else 46 | p = z; 47 | end 48 | 49 | % Sum the result to get 50 | q = ((J'*(W'*W)*J) + regpar*MTX.WTW'*MTX.WTW)*p; 51 | 52 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 53 | 54 | alpha = rho / (p'*q ); 55 | x = x + alpha * p; % update approximation vector 56 | 57 | r = r - alpha*q; % compute residual 58 | err = norm( r ) / rho0; % check convergence 59 | numiter = iter; 60 | fprintf(' PCG iteration %d, Relative residual = %e\n',iter, err); 61 | if ( err <= tol ) 62 | break, 63 | end 64 | res(iter) = err; 65 | 66 | end 67 | disp(' Done pcg -----'); 68 | % END ipcg.m 69 | 70 | -------------------------------------------------------------------------------- /Code/kron3.m: -------------------------------------------------------------------------------- 1 | function K = kron3(A,B,C) 2 | % K = kron3(A,B,C) 3 | %calculates a 3D kronecker product 4 | %A, B, C are vectors of arbitrary length 5 | 6 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 7 | % For more information, go to http://software.seg.org/2007/0001 . 8 | % You must read and accept usage terms at: 9 | % http://software.seg.org/disclaimer.txt before use. 10 | % 11 | % Revision history: 12 | % Original SEG version Eldad Haber 13 | % Last update, July 2003 14 | 15 | ma = length(A); 16 | mb = length(B); 17 | mc = length(C); 18 | 19 | A = reshape(A,ma,1,1); 20 | B = reshape(B,1,mb,1); 21 | C = reshape(C,1,1,mc); 22 | 23 | [ma,na,ka] = size(A); 24 | [mb,nb,kb] = size(B); 25 | [mc,nc,kc] = size(C); 26 | 27 | 28 | t = 0:(ma*mb*mc-1); 29 | ia = fix(t/(mb*mc))+1; 30 | ib = rem(t,mb)+1; 31 | ic = rem(t,mc)+1; 32 | 33 | t = 0:(na*nb*nc-1); 34 | ja = fix(t/(nb*nc))+1; 35 | jb = rem(t,nb)+1; 36 | jc = rem(t,nc)+1; 37 | 38 | t = 0:(ka*kb*kc-1); 39 | ka = fix(t/(kb*kc))+1; 40 | kb = rem(t,kb)+1; 41 | kc = rem(t,kc)+1; 42 | 43 | K = A(ia,ja,ka).*B(ib,jb,kb).*C(ic,jc,kc); 44 | 45 | 46 | -------------------------------------------------------------------------------- /Code/kron33.m: -------------------------------------------------------------------------------- 1 | function K = kron3(A,B,C) 2 | % K = kron3(A,B,C) 3 | %calculates a 3D kronecker product 4 | %A, B, C are vectors of arbitrary length 5 | 6 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 7 | % For more information, go to http://software.seg.org/2007/0001 . 8 | % You must read and accept usage terms at: 9 | % http://software.seg.org/disclaimer.txt before use. 10 | % 11 | % Revision history: 12 | % Original SEG version Eldad Haber 13 | % Last update, July 2003 14 | 15 | ma = length(A); 16 | mb = length(B); 17 | mc = length(C); 18 | 19 | A = reshape(A,ma,1); 20 | B = reshape(B,1,mb,1); 21 | C = reshape(C,1,mc); 22 | 23 | [ma,na,ka] = size(A); 24 | [mb,nb,kb] = size(B); 25 | [mc,nc,kc] = size(C); 26 | 27 | 28 | t = 0:(ma*mc-1); 29 | ia = fix(t/(mc))+1; 30 | ib = rem(t,mb)+1; 31 | ic = rem(t,mc)+1; 32 | 33 | t = 0:(na*nc-1); 34 | ja = fix(t/(nc))+1; 35 | jb = rem(t,nb)+1; 36 | jc = rem(t,nc)+1; 37 | 38 | t = 0:(ka*kc-1); 39 | ka = fix(t/(kc))+1; 40 | kb = rem(t,kb)+1; 41 | kc = rem(t,kc)+1; 42 | 43 | K = A(ia,ja,ka).*B(ib,jb,kb).*C(ic,jc,kc); 44 | 45 | 46 | -------------------------------------------------------------------------------- /Code/matsol.m: -------------------------------------------------------------------------------- 1 | function[u,iter] = matsol(A,q,tol) 2 | % [u] = matsol(A,q,tol) 3 | % solves the linear system u = A^-1*q 4 | % Uses an SSOR preconditioner and either precg or bicstb. 5 | % Solve using ssor preconditioner 6 | % 7 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 8 | % For more information, go to http://software.seg.org/2007/0001 . 9 | % You must read and accept usage terms at: 10 | % http://software.seg.org/disclaimer.txt before use. 11 | % 12 | % Revision history: 13 | % Original SEG version by Adam Pidlisecky and Eldad Haber 14 | % Last update, July 2006 15 | 16 | if norm(q) < 1e-14, 17 | u = q*0; 18 | return; 19 | end; 20 | 21 | %Generate the preconditioner 22 | % SSOR preconditioner 23 | Dg = spdiags(diag(A),0,size(A,1),size(A,2)); 24 | Dhf = spdiags(1./sqrt(diag(A)),0,size(A,1),size(A,2)); 25 | M1 = (Dg + tril(A,-1)) * Dhf; 26 | M2 = Dhf * (Dg + triu(A,1)); 27 | 28 | %Check to see which solver to use (see if the problem is self adjoint) 29 | if norm(A-A','fro') < 1e-14 30 | [u, iter] = precg(A, q, M1, M2, 500, tol); 31 | else 32 | [u, err1,iter] = bicgstb(A, q, M1, M2, 500, tol); 33 | end -------------------------------------------------------------------------------- /Code/mkvc.m: -------------------------------------------------------------------------------- 1 | function[v] = mkvc(A) 2 | % function to convert from a matrix to a vector 3 | v = A(:); -------------------------------------------------------------------------------- /Code/modelInv_parms.dat: -------------------------------------------------------------------------------- 1 | 10.00 2 | 500.00 3 | 2.00 4 | 10.000000000000000 5 | 10.000000000000000 6 | 15.000000000000000 7 | 5.00 8 | 0.00 9 | 0.00 10 | 1.00 11 | 1.00 12 | 1.00 13 | 1.000000 14 | 0.000000 15 | 1.000000 16 | 0.000000 17 | -------------------------------------------------------------------------------- /Code/new_calibration.m: -------------------------------------------------------------------------------- 1 | function [rawGem, calGem, filtGem]=new_calibration(dcale,dobsy,f,r,q,vall) 2 | %dcal = prdGEM; % data you are calibrating to (predicted response to the DC model) 3 | %dobs = obsGEM; % data you want to calibrate (the observed GEM) 4 | isOpen = matlabpool('size') > 0;%plotdoi=0; 5 | fprintf('****** STARTING THE RAW DATA FILTERING AND CALIBRATION PROCESS ******\n'); 6 | if isOpen==0 7 | matlabpool('local',vall) 8 | end 9 | % predicted response 10 | m=mean(dcale(:,4)); 11 | parfor ii=1:length(f) 12 | depth(ii)=503/sqrt(f(ii)*m); 13 | d2(:,ii)=abs(dcale(:,3)-depth(ii)); 14 | ff=min(d2(:,ii)); 15 | fdepth(:,ii)=find(d2(:,ii)==ff); 16 | end 17 | fdepth=fdepth';fdepth=fdepth(:); 18 | dcale2(:,1)=dcale(fdepth,1); 19 | dcale2(:,2)=dcale(fdepth,2); 20 | dcale2(:,3)=dcale(fdepth,3); 21 | dcale2(:,4)=dcale(fdepth,4);dcale=dcale2; 22 | xx=(dcale(:,1));yy=(dcale(:,2));dd=dcale(:,3); 23 | dcall=dcale(:,4);dcali=reshape(dcall,length(f),length(dd)/length(f));%dlmwrite('dcali.dat',dcali); 24 | warning off 25 | 26 | dobss=dobsy(:,8);xx2=dobsy(:,1);yy2=dobsy(:,2); 27 | rawGem=dobss; 28 | coor1=[xx,yy]; 29 | coor2=[xx2,yy2]; 30 | [m n]=size(coor1); 31 | [ma na]=size(coor2); 32 | 33 | for i=1:m 34 | parfor j=1:ma 35 | bo(j,i)=sum(abs(coor1(i,:)-coor2(j,:))); 36 | end 37 | end 38 | 39 | [mm nn]=size(bo); 40 | for ii=1:nn 41 | ba=bo(:,ii); 42 | boo(ii)=min(find(ba==min(ba))); 43 | end 44 | dcali=dcali(:);dcali2=reshape(dcali,length(f),length(dcali)/length(f)); 45 | [dcal]=FEMIC_forward2D(dcali2,depth,vall);dcal=dcal'; 46 | fprintf('okforward') 47 | dobsa=dobss(boo); 48 | dobs=reshape(dobsa,length(f),length(dobsa)/length(f));dobs=dobs'; 49 | ns = size(dobs,1); % soundings 50 | nf = size(dobs,2); % frequencies 51 | % initial values 52 | G = ones(1,nf); % gain 53 | B = zeros(1,nf); % bias 54 | dprd = (dcal + repmat(B,ns,1))*diag(G); 55 | 56 | % weights - leave at ones for now... it works, but should be fixed 57 | wd = ones(1,nf); % enter 1/sigma values 58 | wm = [1 1]; % G, B 59 | 60 | % build block matrices - kind of klugey for now... 61 | for i=1:nf 62 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 63 | A(i).D = dobs(:,i) - dprd(:,i); 64 | A(i).Wd = wd(i)*eye(ns); 65 | A(i).Wm = diag(wm); 66 | A(i).m = [G(i);B(i)]; 67 | end 68 | J = blkdiag(A.J); 69 | D = blkdiag(A.D); 70 | Wd = blkdiag(A.Wd); 71 | Wm = blkdiag(A.Wm); 72 | m = blkdiag(A.m); 73 | m0 = blkdiag(A.m); 74 | 75 | 76 | %% solve 77 | for n = 1:10 78 | 79 | H = J'*Wd'*Wd*J + Wm'*Wm; 80 | r = J'*Wd'*D + Wm'*Wm*(m-m0); 81 | 82 | % calculate update 83 | dm = H\r; 84 | m = m + dm; 85 | G = G + diag(dm(1:2:end,:)).'; 86 | B = B + diag(dm(2:2:end,:)).'; 87 | 88 | % update predicted & calibrated data 89 | dprd = (dcal + repmat(B,ns,1))*diag(G); 90 | dcor = dobs*diag(1./G) - repmat(B,ns,1);calGem=dcor; 91 | 92 | % update block matrices - kind of klugey for now... 93 | for i=1:nf 94 | A(i).J = [(dcal(:,i) + B(i)) G(i)*ones(ns,1)]; 95 | A(i).D = dobs(:,i) - dprd(:,i); 96 | end 97 | J = blkdiag(A.J); 98 | D = blkdiag(A.D); 99 | 100 | % misfit 101 | err(n,:) = diag(D'*(Wd'*Wd)*D); 102 | 103 | end 104 | dcor=dcor';dcor2=dcor(:); 105 | dobss(boo)=dcor2;%dlmwrite('dob.dat',dobss); 106 | 107 | 108 | %% PCA filter 109 | dcorr=reshape(dobss,length(f),length(dobss)/length(f));%length(find(xx2==xx2(1))),length(dobss)/length(find(xx2==xx2(1))));dcorr=dcorr'; 110 | m = mean(dcorr.',2);ns=length(f); 111 | M = repmat(m,1,ns); 112 | [u,s,v] = svd(dcorr.' - M); 113 | lp = u(:,1)*u(:,1)'*(dcorr.'-M) + M; filtGem=lp;% 1st component only 114 | Filtered_data=dobsy;Filtered_data(:,8)=lp(:); 115 | dlmwrite('Filtered_data.dat',Filtered_data,'precision','%12.5f'); 116 | fprintf('****** THE RAW DATA HAS BEEN FILTERED AND CALIBRATED SUCCESSFULLY ******\n'); 117 | -------------------------------------------------------------------------------- /Code/newgradient.m: -------------------------------------------------------------------------------- 1 | function [Gx, Gz]=newgradient(x,z) 2 | 3 | %mesh.num_param - (x-1)*(z-1) 4 | %tmp_x # of x parameters -1 (center values) 5 | %tmp_z # of z parameters -1 (center values) 6 | 7 | mesh.num_param=length(x)*length(z); 8 | for i=1:length(z) 9 | mesh.param_x(:,i)=x; 10 | end 11 | mesh.param_x=mesh.param_x(:); 12 | for i=1:length(z) 13 | mesh.param_y(:,i)=z(i)*ones(length(x),1); 14 | end 15 | mesh.param_y=mesh.param_y(:); 16 | c=zeros(mesh.num_param,mesh.num_param); 17 | cx=zeros(mesh.num_param,mesh.num_param); 18 | cy=zeros(mesh.num_param,mesh.num_param); 19 | 20 | % tmp_x=union(mesh.tmp_param(:,1),mesh.tmp_param(:,1)); 21 | % tmp_y=union(mesh.tmp_param(:,2),mesh.tmp_param(:,2)); 22 | 23 | 24 | tmp_x=unique(mesh.param_x); 25 | tmp_y=unique(mesh.param_y); 26 | 27 | 28 | 29 | for i=1:mesh.num_param 30 | 31 | current_x=mesh.param_x(i); 32 | current_y=mesh.param_y(i); 33 | ind=find(tmp_x==current_x); 34 | % search all other parameters that have the same y and the x=ind+1 35 | for j=1:mesh.num_param 36 | if ind~=length(tmp_x) 37 | if mesh.param_y(j)==current_y && mesh.param_x(j)==tmp_x(ind+1) 38 | cx(i,j)=1; 39 | % cx(i,j)=sqrt( (mesh.tmp_param(j,6)-mesh.tmp_param(j,5))/ ( mesh.tmp_param(j,1)-mesh.tmp_param(i,1))); 40 | end 41 | end 42 | end 43 | end 44 | 45 | for i=1:mesh.num_param 46 | cx(i,i)=-sum(cx(i,:)); 47 | end 48 | 49 | 50 | ctc1=cx'*cx; 51 | 52 | 53 | for i=1:mesh.num_param 54 | 55 | current_x=mesh.param_x(i); 56 | current_y=mesh.param_y(i); 57 | ind=find(tmp_y==current_y); 58 | % search all other parameters that have the same y and the x=ind+1 59 | for j=1:mesh.num_param 60 | if ind~=length(tmp_y) 61 | if mesh.param_y(j)==tmp_y(ind+1) && mesh.param_x(j)==current_x 62 | cy(i,j)=1; 63 | % cy(i,j)=sqrt( (mesh.tmp_param(j,4)-mesh.tmp_param(j,3))/ ( mesh.param_y(j)-mesh.param_y(i)) ); 64 | end 65 | end 66 | end 67 | end 68 | 69 | for i=1:mesh.num_param 70 | cy(i,i)=-sum(cy(i,:)); 71 | end 72 | Gx=cx; 73 | Gz=cy; -------------------------------------------------------------------------------- /Code/precg.m: -------------------------------------------------------------------------------- 1 | function [x,iter] = precg(A, b, M1, M2, max_it, tol) 2 | % [x,numiter] = precg(A, b, M1, M2, max_it, tol) 3 | % 4 | % Preconditioned CG solver 5 | % 6 | 7 | % Copyright (c) 2007 by the Society of Exploration Geophysicists. 8 | % For more information, go to http://software.seg.org/2007/0001 . 9 | % You must read and accept usage terms at: 10 | % http://software.seg.org/disclaimer.txt before use. 11 | % 12 | % Revision history: 13 | % Original SEG version by Adam Pidlisecky and Eldad Haber 14 | % Last update, July 2006 15 | 16 | 17 | %initialize the starting variables 18 | r = b; 19 | n = length(b); 20 | x = zeros(n,1); 21 | rho = r'*r; 22 | 23 | if ( rho == 0.0 ), rho = 1.0; end 24 | 25 | err = norm( r ) / sqrt(rho); 26 | if ( err < tol ) disp('err < tol'); return, end 27 | 28 | for iter = 1:max_it % begin iteration 29 | 30 | % preconditioning step %%% 31 | z = M2\(M1\r); 32 | 33 | rho_1 = rho; 34 | rho = (r'*z); 35 | if iter == 1, rho0 = norm(z); end; 36 | 37 | if ( iter > 1 ), % Calculate the direction vector 38 | beta = rho / rho_1; 39 | p = z + beta*p; 40 | else 41 | p = z; 42 | end 43 | %%%%%% Matrix times a vector %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 44 | % q = A*p 45 | q = A*p; 46 | 47 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 48 | 49 | alpha = rho / (p'*q ); 50 | x = x + alpha * p; % update approximation vector 51 | 52 | r = r - alpha*q; % compute residual 53 | err = norm( r ) / rho0; % check convergence 54 | numiter = iter; 55 | %fprintf(' PRECG iteration %d, Relative residual = %e\n',iter, err); 56 | if ( err <= tol ) 57 | break, 58 | end 59 | res(iter) = err; 60 | 61 | end 62 | %END precg.m 63 | 64 | -------------------------------------------------------------------------------- /Code/progressbar.m: -------------------------------------------------------------------------------- 1 | function progressbar(varargin) 2 | % Description: 3 | % progressbar() provides an indication of the progress of some task using 4 | % graphics and text. Calling progressbar repeatedly will update the figure and 5 | % automatically estimate the amount of time remaining. 6 | % This implementation of progressbar is intended to be extremely simple to use 7 | % while providing a high quality user experience. 8 | % 9 | % Features: 10 | % - Can add progressbar to existing m-files with a single line of code. 11 | % - Supports multiple bars in one figure to show progress of nested loops. 12 | % - Optional labels on bars. 13 | % - Figure closes automatically when task is complete. 14 | % - Only one figure can exist so old figures don't clutter the desktop. 15 | % - Remaining time estimate is accurate even if the figure gets closed. 16 | % - Minimal execution time. Won't slow down code. 17 | % - Randomized color. When a programmer gets bored... 18 | % 19 | % Example Function Calls For Single Bar Usage: 20 | % progressbar % Initialize/reset 21 | % progressbar(0) % Initialize/reset 22 | % progressbar('Label') % Initialize/reset and label the bar 23 | % progressbar(0.5) % Update 24 | % progressbar(1) % Close 25 | % 26 | % Example Function Calls For Multi Bar Usage: 27 | % progressbar(0, 0) % Initialize/reset two bars 28 | % progressbar('A', '') % Initialize/reset two bars with one label 29 | % progressbar('', 'B') % Initialize/reset two bars with one label 30 | % progressbar('A', 'B') % Initialize/reset two bars with two labels 31 | % progressbar(0.3) % Update 1st bar 32 | % progressbar(0.3, []) % Update 1st bar 33 | % progressbar([], 0.3) % Update 2nd bar 34 | % progressbar(0.7, 0.9) % Update both bars 35 | % progressbar(1) % Close 36 | % progressbar(1, []) % Close 37 | % progressbar(1, 0.4) % Close 38 | % 39 | % Notes: 40 | % For best results, call progressbar with all zero (or all string) inputs 41 | % before any processing. This sets the proper starting time reference to 42 | % calculate time remaining. 43 | % Bar color is choosen randomly when the figure is created or reset. Clicking 44 | % the bar will cause a random color change. 45 | % 46 | % Demos: 47 | % % Single bar 48 | % m = 500; 49 | % progressbar % Init single bar 50 | % for i = 1:m 51 | % pause(0.01) % Do something important 52 | % progressbar(i/m) % Update progress bar 53 | % end 54 | % 55 | % % Simple multi bar (update one bar at a time) 56 | % m = 4; 57 | % n = 3; 58 | % p = 100; 59 | % progressbar(0,0,0) % Init 3 bars 60 | % for i = 1:m 61 | % progressbar([],0) % Reset 2nd bar 62 | % for j = 1:n 63 | % progressbar([],[],0) % Reset 3rd bar 64 | % for k = 1:p 65 | % pause(0.01) % Do something important 66 | % progressbar([],[],k/p) % Update 3rd bar 67 | % end 68 | % progressbar([],j/n) % Update 2nd bar 69 | % end 70 | % progressbar(i/m) % Update 1st bar 71 | % end 72 | % 73 | % % Fancy multi bar (use labels and update all bars at once) 74 | % m = 4; 75 | % n = 3; 76 | % p = 100; 77 | % progressbar('Monte Carlo Trials','Simulation','Component') % Init 3 bars 78 | % for i = 1:m 79 | % for j = 1:n 80 | % for k = 1:p 81 | % pause(0.01) % Do something important 82 | % % Update all bars 83 | % frac3 = k/p; 84 | % frac2 = ((j-1) + frac3) / n; 85 | % frac1 = ((i-1) + frac2) / m; 86 | % progressbar(frac1, frac2, frac3) 87 | % end 88 | % end 89 | % end 90 | % 91 | % Author: 92 | % Steve Hoelzer 93 | % 94 | % Revisions: 95 | % 2002-Feb-27 Created function 96 | % 2002-Mar-19 Updated title text order 97 | % 2002-Apr-11 Use floor instead of round for percentdone 98 | % 2002-Jun-06 Updated for speed using patch (Thanks to waitbar.m) 99 | % 2002-Jun-19 Choose random patch color when a new figure is created 100 | % 2002-Jun-24 Click on bar or axes to choose new random color 101 | % 2002-Jun-27 Calc time left, reset progress bar when fractiondone == 0 102 | % 2002-Jun-28 Remove extraText var, add position var 103 | % 2002-Jul-18 fractiondone input is optional 104 | % 2002-Jul-19 Allow position to specify screen coordinates 105 | % 2002-Jul-22 Clear vars used in color change callback routine 106 | % 2002-Jul-29 Position input is always specified in pixels 107 | % 2002-Sep-09 Change order of title bar text 108 | % 2003-Jun-13 Change 'min' to 'm' because of built in function 'min' 109 | % 2003-Sep-08 Use callback for changing color instead of string 110 | % 2003-Sep-10 Use persistent vars for speed, modify titlebarstr 111 | % 2003-Sep-25 Correct titlebarstr for 0% case 112 | % 2003-Nov-25 Clear all persistent vars when percentdone = 100 113 | % 2004-Jan-22 Cleaner reset process, don't create figure if percentdone = 100 114 | % 2004-Jan-27 Handle incorrect position input 115 | % 2004-Feb-16 Minimum time interval between updates 116 | % 2004-Apr-01 Cleaner process of enforcing minimum time interval 117 | % 2004-Oct-08 Seperate function for timeleftstr, expand to include days 118 | % 2004-Oct-20 Efficient if-else structure for sec2timestr 119 | % 2006-Sep-11 Width is a multiple of height (don't stretch on widescreens) 120 | % 2010-Sep-21 Major overhaul to support multiple bars and add labels 121 | % 122 | 123 | persistent progfig progdata lastupdate 124 | 125 | % Get inputs 126 | if nargin > 0 127 | input = varargin; 128 | ninput = nargin; 129 | else 130 | % If no inputs, init with a single bar 131 | input = {0}; 132 | ninput = 1; 133 | end 134 | 135 | % If task completed, close figure and clear vars, then exit 136 | if input{1} == 1 137 | if ishandle(progfig) 138 | delete(progfig) % Close progress bar 139 | end 140 | clear progfig progdata lastupdate % Clear persistent vars 141 | drawnow 142 | return 143 | end 144 | 145 | % Init reset flag 146 | resetflag = false; 147 | 148 | % Set reset flag if first input is a string 149 | if ischar(input{1}) 150 | resetflag = true; 151 | end 152 | 153 | % Set reset flag if all inputs are zero 154 | if input{1} == 0 155 | % If the quick check above passes, need to check all inputs 156 | if all([input{:}] == 0) && (length([input{:}]) == ninput) 157 | resetflag = true; 158 | end 159 | end 160 | 161 | % Set reset flag if more inputs than bars 162 | if ninput > length(progdata) 163 | resetflag = true; 164 | end 165 | 166 | % If reset needed, close figure and forget old data 167 | if resetflag 168 | if ishandle(progfig) 169 | delete(progfig) % Close progress bar 170 | end 171 | progfig = []; 172 | progdata = []; % Forget obsolete data 173 | end 174 | 175 | % Create new progress bar if needed 176 | if ishandle(progfig) 177 | else % This strange if-else works when progfig is empty (~ishandle() does not) 178 | 179 | % Define figure size and axes padding for the single bar case 180 | height = 0.03; 181 | width = height * 8; 182 | hpad = 0.02; 183 | vpad = 0.25; 184 | 185 | % Figure out how many bars to draw 186 | nbars = max(ninput, length(progdata)); 187 | 188 | % Adjust figure size and axes padding for number of bars 189 | heightfactor = (1 - vpad) * nbars + vpad; 190 | height = height * heightfactor; 191 | vpad = vpad / heightfactor; 192 | 193 | % Initialize progress bar figure 194 | left = (1 - width) / 2; 195 | bottom = (1 - height) / 2; 196 | progfig = figure(... 197 | 'Units', 'normalized',... 198 | 'Position', [left bottom width height],... 199 | 'NumberTitle', 'off',... 200 | 'Resize', 'off',... 201 | 'MenuBar', 'none' ); 202 | 203 | % Initialize axes, patch, and text for each bar 204 | left = hpad; 205 | width = 1 - 2*hpad; 206 | vpadtotal = vpad * (nbars + 1); 207 | height = (1 - vpadtotal) / nbars; 208 | for ndx = 1:nbars 209 | % Create axes, patch, and text 210 | bottom = vpad + (vpad + height) * (nbars - ndx); 211 | progdata(ndx).progaxes = axes( ... 212 | 'Position', [left bottom width height], ... 213 | 'XLim', [0 1], ... 214 | 'YLim', [0 1], ... 215 | 'Box', 'on', ... 216 | 'ytick', [], ... 217 | 'xtick', [] ); 218 | progdata(ndx).progpatch = patch( ... 219 | 'XData', [0 0 0 0], ... 220 | 'YData', [0 0 1 1] ); 221 | progdata(ndx).progtext = text(0.99, 0.5, '', ... 222 | 'HorizontalAlignment', 'Right', ... 223 | 'FontUnits', 'Normalized', ... 224 | 'FontSize', 0.7 ); 225 | progdata(ndx).proglabel = text(0.01, 0.5, '', ... 226 | 'HorizontalAlignment', 'Left', ... 227 | 'FontUnits', 'Normalized', ... 228 | 'FontSize', 0.7 ); 229 | if ischar(input{ndx}) 230 | set(progdata(ndx).proglabel, 'String', input{ndx}) 231 | input{ndx} = 0; 232 | end 233 | 234 | % Set callbacks to change color on mouse click 235 | set(progdata(ndx).progaxes, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) 236 | set(progdata(ndx).progpatch, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) 237 | set(progdata(ndx).progtext, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) 238 | set(progdata(ndx).proglabel, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) 239 | 240 | % Pick a random color for this patch 241 | changecolor([], [], progdata(ndx).progpatch) 242 | 243 | % Set starting time reference 244 | if ~isfield(progdata(ndx), 'starttime') || isempty(progdata(ndx).starttime) 245 | progdata(ndx).starttime = clock; 246 | end 247 | end 248 | 249 | % Set time of last update to ensure a redraw 250 | lastupdate = clock - 1; 251 | 252 | end 253 | 254 | % Process inputs and update state of progdata 255 | for ndx = 1:ninput 256 | if ~isempty(input{ndx}) 257 | progdata(ndx).fractiondone = input{ndx}; 258 | progdata(ndx).clock = clock; 259 | end 260 | end 261 | 262 | % Enforce a minimum time interval between graphics updates 263 | myclock = clock; 264 | if abs(myclock(6) - lastupdate(6)) < 0.01 % Could use etime() but this is faster 265 | return 266 | end 267 | 268 | % Update progress patch 269 | for ndx = 1:length(progdata) 270 | set(progdata(ndx).progpatch, 'XData', ... 271 | [0, progdata(ndx).fractiondone, progdata(ndx).fractiondone, 0]) 272 | end 273 | 274 | % Update progress text if there is more than one bar 275 | if length(progdata) > 1 276 | for ndx = 1:length(progdata) 277 | set(progdata(ndx).progtext, 'String', ... 278 | sprintf('%1d%%', floor(100*progdata(ndx).fractiondone))) 279 | end 280 | end 281 | 282 | % Update progress figure title bar 283 | if progdata(1).fractiondone > 0 284 | runtime = etime(progdata(1).clock, progdata(1).starttime); 285 | timeleft = runtime / progdata(1).fractiondone - runtime; 286 | timeleftstr = sec2timestr(timeleft); 287 | titlebarstr = sprintf('%2d%% %s remaining', ... 288 | floor(100*progdata(1).fractiondone), timeleftstr); 289 | else 290 | titlebarstr = ' 0%'; 291 | end 292 | set(progfig, 'Name', titlebarstr) 293 | 294 | % Force redraw to show changes 295 | drawnow 296 | 297 | % Record time of this update 298 | lastupdate = clock; 299 | 300 | 301 | % ------------------------------------------------------------------------------ 302 | function changecolor(h, e, progpatch) %#ok 303 | % Change the color of the progress bar patch 304 | 305 | % Prevent color from being too dark or too light 306 | colormin = 1.5; 307 | colormax = 2.8; 308 | 309 | thiscolor = rand(1, 3); 310 | while (sum(thiscolor) < colormin) || (sum(thiscolor) > colormax) 311 | thiscolor = rand(1, 3); 312 | end 313 | 314 | set(progpatch, 'FaceColor', thiscolor) 315 | 316 | 317 | % ------------------------------------------------------------------------------ 318 | function timestr = sec2timestr(sec) 319 | % Convert a time measurement from seconds into a human readable string. 320 | 321 | % Convert seconds to other units 322 | w = floor(sec/604800); % Weeks 323 | sec = sec - w*604800; 324 | d = floor(sec/86400); % Days 325 | sec = sec - d*86400; 326 | h = floor(sec/3600); % Hours 327 | sec = sec - h*3600; 328 | m = floor(sec/60); % Minutes 329 | sec = sec - m*60; 330 | s = floor(sec); % Seconds 331 | 332 | % Create time string 333 | if w > 0 334 | if w > 9 335 | timestr = sprintf('%d week', w); 336 | else 337 | timestr = sprintf('%d week, %d day', w, d); 338 | end 339 | elseif d > 0 340 | if d > 9 341 | timestr = sprintf('%d day', d); 342 | else 343 | timestr = sprintf('%d day, %d hr', d, h); 344 | end 345 | elseif h > 0 346 | if h > 9 347 | timestr = sprintf('%d hr', h); 348 | else 349 | timestr = sprintf('%d hr, %d min', h, m); 350 | end 351 | elseif m > 0 352 | if m > 9 353 | timestr = sprintf('%d min', m); 354 | else 355 | timestr = sprintf('%d min, %d sec', m, s); 356 | end 357 | else 358 | timestr = sprintf('%d sec', s); 359 | end 360 | -------------------------------------------------------------------------------- /Code/result.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/result.mat -------------------------------------------------------------------------------- /Code/sense.dat: -------------------------------------------------------------------------------- 1 | -88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88546,-25694,-6548.2,-1023.5,-12.543,-88546,-25694,-6548.2,-1023.5,-12.543,-88546,-25694,-6548.2,-1023.5,-12.543,-88546,-25694,-6548.2,-1023.5,-12.543,-88546,-25694,-6548.2,-1023.5,-12.543,-90387,-26960,-6411.5,-1083.1,-108.33,-59452,-41556,-6756.1,-341.11,146.54,-59622,-41614,-6762.3,-341.4,146.76,-59631,-41615,-6762.6,-341.46,146.75,-59641,-41616,-6762.8,-341.54,146.74,-90378,-26960,-6410.6,-1082.8,-108.24,-90388,-26959,-6411.2,-1083.1,-108.32,-90379,-26960,-6410.8,-1082.8,-108.25,-90388,-26959,-6411.2,-1083.1,-108.33,-90388,-26959,-6411.3,-1083.1,-108.33,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836,-88629,-25679,-6545.3,-1025.3,-13.836 2 | -------------------------------------------------------------------------------- /Code/smooth_mtx_surface4444.m: -------------------------------------------------------------------------------- 1 | function mesh=smooth_mtx_surface4444(input,mesh,W,mm,nn,sx,sz) 2 | %WW12=w12; 3 | %WW13=w13+w23+w14+w12; 4 | %Wt12 = spdiags((WW12), 0, mm*nn, mm*nn); 5 | Wt13 = spdiags((W), 0, mm*nn, mm*nn); 6 | %Wt14 = spdiags((w14), 0, mm*nn, mm*nn); 7 | %Wt23 = spdiags((w23), 0, mm*nn, mm*nn); 8 | 9 | 10 | c=zeros(mesh.num_param,mesh.num_param); 11 | cx=zeros(mesh.num_param,mesh.num_param); 12 | cy=zeros(mesh.num_param,mesh.num_param); 13 | 14 | % tmp_x=union(mesh.tmp_param(:,1),mesh.tmp_param(:,1)); 15 | % tmp_y=union(mesh.tmp_param(:,2),mesh.tmp_param(:,2)); 16 | 17 | 18 | tmp_x=unique(mesh.param_x); 19 | tmp_y=unique(mesh.param_y); 20 | 21 | 22 | 23 | for i=1:mesh.num_param 24 | 25 | current_x=mesh.param_x(i); 26 | current_y=mesh.param_y(i); 27 | ind=find(tmp_x==current_x); 28 | % search all other parameters that have the same y and the x=ind+1 29 | for j=1:mesh.num_param 30 | if ind~=length(tmp_x) 31 | if mesh.param_y(j)==current_y && mesh.param_x(j)==tmp_x(ind+1) 32 | cx(i,j)=1; 33 | % cx(i,j)=sqrt( (mesh.tmp_param(j,6)-mesh.tmp_param(j,5))/ ( mesh.tmp_param(j,1)-mesh.tmp_param(i,1))); 34 | end 35 | end 36 | end 37 | end 38 | 39 | for i=1:mesh.num_param 40 | cx(i,i)=-sum(cx(i,:)); 41 | end 42 | 43 | 44 | ctc1=cx'*cx; 45 | 46 | 47 | for i=1:mesh.num_param 48 | 49 | current_x=mesh.param_x(i); 50 | current_y=mesh.param_y(i); 51 | ind=find(tmp_y==current_y); 52 | % search all other parameters that have the same y and the x=ind+1 53 | for j=1:mesh.num_param 54 | if ind~=length(tmp_y) 55 | if mesh.param_y(j)==tmp_y(ind+1) && mesh.param_x(j)==current_x 56 | cy(i,j)=1; 57 | % cy(i,j)=sqrt( (mesh.tmp_param(j,4)-mesh.tmp_param(j,3))/ ( mesh.param_y(j)-mesh.param_y(i)) ); 58 | end 59 | end 60 | end 61 | end 62 | 63 | for i=1:mesh.num_param 64 | cy(i,i)=-sum(cy(i,:)); 65 | end 66 | 67 | 68 | ctc2=cy'*cy; 69 | 70 | 71 | mesh.ctc=sx*cx'*(Wt13'*Wt13)*cx+sz*cy'*(Wt13'*Wt13)*cy;%ctc1+ctc2; 72 | 73 | 74 | %ctc=eye(num_param,num_param); 75 | 76 | %/* adjust weighting at the edges */ 77 | 78 | % if smooth_type==11 79 | % for i=1:num_param 80 | % s1=0; 81 | % for j=1:num_param 82 | % if(c(i,j)~=0) s1=s1+1; end 83 | % end 84 | % if(s1<=2) c(i,i)=1.15*c(i,j); end 85 | % end 86 | % 87 | % end 88 | 89 | 90 | 91 | 92 | % This matrix has no meaning. I just calculate so I can now the elemeents 93 | % that do not have zero. After this I can calcualte the S matrix (ACB, Kim) 94 | c=cx+cy; 95 | c=mesh.ctc; 96 | % /*Here i calculate the S matrix, which is one when C is non zero and zero otherwise*/ 97 | for i=1:mesh.num_param 98 | 99 | for j=1:mesh.num_param 100 | 101 | if (c(i,j)~=0) 102 | mesh.S(i,j)=1; 103 | else 104 | mesh.S(i,j)=0; 105 | end 106 | end 107 | end 108 | 109 | 110 | % Here create time related constarain matrix M 111 | if input.time_lapse_flag==1 112 | mesh.M=eye(input.num_files*mesh.num_param,input.num_files*mesh.num_param); 113 | for i=1:input.num_files*mesh.num_param 114 | for j=1:input.num_files*mesh.num_param 115 | 116 | if j-i==mesh.num_param 117 | mesh.M(i,j)=-1; 118 | end 119 | 120 | if i==j && i>(input.num_files-1)*mesh.num_param && j>(input.num_files-1)*mesh.num_param 121 | mesh.M(i,j)=0; 122 | end 123 | end 124 | end 125 | 126 | end 127 | 128 | 129 | 130 | end 131 | 132 | -------------------------------------------------------------------------------- /Code/start.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Code/start.fig -------------------------------------------------------------------------------- /Data-sets/Data: -------------------------------------------------------------------------------- 1 | Data 2 | -------------------------------------------------------------------------------- /Data-sets/Field-WY/READ ME.txt: -------------------------------------------------------------------------------- 1 | The WY data folder contains this READ ME file and two additional files for the Wyoming data set in the paper: 2 | 3 | 1) Input_WY_data.dat: A text (ascii) file containing the input data, with columns of: 4 | - x location in meters 5 | - y location in meters 6 | - z location in meters 7 | - sounding identification (ID) #, with different data at same location sharing a sounding ID 8 | - frequency, in hertz 9 | - Standard error, in data units 10 | - coil configration, 1 for vertical dipole, 2 for horizontal dipole, or 3 for both 11 | - list of apparent conductivity values for each frequency, in milliSiemens/meter 12 | 13 | 14 | 2) Initial model.dat: A text (ascii) file containing initial FEMIC models for this example, with columns of: 15 | - x location in meters 16 | - y location in meters 17 | - z location in meters 18 | - sounding identification 19 | - layer number 20 | - initial conductivity value, in milliSiemens/meter for each layer 21 | - additional rows for alternative starting models 22 | -------------------------------------------------------------------------------- /Data-sets/Field-WY/data: -------------------------------------------------------------------------------- 1 | data 2 | -------------------------------------------------------------------------------- /Data-sets/Synthetic/Input_femic.dat: -------------------------------------------------------------------------------- 1 | 1,0,0,1,1530,1,1,1.0671251044053824+52.019337326549561i 2 | 1,0,0,1,8250,1,1,12.473955446320245+272.6373337925026i 3 | 1,0,0,1,20370,1,1,45.578137561435831+654.28089056049589i 4 | 1,0,0,1,33030,1,1,90.273016061787146+1038.5053084437895i 5 | 1,0,0,1,47970,1,1,152.14834054852491+1477.8324093439965i 6 | 1,0,0,1,63090,1,1,222.42797691382899+1909.8641493261644i 7 | 1,0,0,1,93090,1,1,379.14882482319911+2736.5436896050605i 8 | 2,0,0,2,1530,1,1,1.0671251044053824+52.019337326549561i 9 | 2,0,0,2,8250,1,1,12.473955446320245+272.6373337925026i 10 | 2,0,0,2,20370,1,1,45.578137561435831+654.28089056049589i 11 | 2,0,0,2,33030,1,1,90.273016061787146+1038.5053084437895i 12 | 2,0,0,2,47970,1,1,152.14834054852491+1477.8324093439965i 13 | 2,0,0,2,63090,1,1,222.42797691382899+1909.8641493261644i 14 | 2,0,0,2,93090,1,1,379.14882482319911+2736.5436896050605i 15 | 3,0,0,3,1530,1,1,1.0671251044053824+52.019337326549561i 16 | 3,0,0,3,8250,1,1,12.473955446320245+272.6373337925026i 17 | 3,0,0,3,20370,1,1,45.578137561435831+654.28089056049589i 18 | 3,0,0,3,33030,1,1,90.273016061787146+1038.5053084437895i 19 | 3,0,0,3,47970,1,1,152.14834054852491+1477.8324093439965i 20 | 3,0,0,3,63090,1,1,222.42797691382899+1909.8641493261644i 21 | 3,0,0,3,93090,1,1,379.14882482319911+2736.5436896050605i 22 | 4,0,0,4,1530,1,1,1.0671251044053824+52.019337326549561i 23 | 4,0,0,4,8250,1,1,12.473955446320245+272.6373337925026i 24 | 4,0,0,4,20370,1,1,45.578137561435831+654.28089056049589i 25 | 4,0,0,4,33030,1,1,90.273016061787146+1038.5053084437895i 26 | 4,0,0,4,47970,1,1,152.14834054852491+1477.8324093439965i 27 | 4,0,0,4,63090,1,1,222.42797691382899+1909.8641493261644i 28 | 4,0,0,4,93090,1,1,379.14882482319911+2736.5436896050605i 29 | 5,0,0,5,1530,1,1,1.0671251044053824+52.019337326549561i 30 | 5,0,0,5,8250,1,1,12.473955446320245+272.6373337925026i 31 | 5,0,0,5,20370,1,1,45.578137561435831+654.28089056049589i 32 | 5,0,0,5,33030,1,1,90.273016061787146+1038.5053084437895i 33 | 5,0,0,5,47970,1,1,152.14834054852491+1477.8324093439965i 34 | 5,0,0,5,63090,1,1,222.42797691382899+1909.8641493261644i 35 | 5,0,0,5,93090,1,1,379.14882482319911+2736.5436896050605i 36 | 6,0,0,6,1530,1,1,1.0671251044053824+52.019337326549561i 37 | 6,0,0,6,8250,1,1,12.473955446320245+272.6373337925026i 38 | 6,0,0,6,20370,1,1,45.578137561435831+654.28089056049589i 39 | 6,0,0,6,33030,1,1,90.273016061787146+1038.5053084437895i 40 | 6,0,0,6,47970,1,1,152.14834054852491+1477.8324093439965i 41 | 6,0,0,6,63090,1,1,222.42797691382899+1909.8641493261644i 42 | 6,0,0,6,93090,1,1,379.14882482319911+2736.5436896050605i 43 | 7,0,0,7,1530,1,1,1.0671251044053824+52.019337326549561i 44 | 7,0,0,7,8250,1,1,12.473955446320245+272.6373337925026i 45 | 7,0,0,7,20370,1,1,45.578137561435831+654.28089056049589i 46 | 7,0,0,7,33030,1,1,90.273016061787146+1038.5053084437895i 47 | 7,0,0,7,47970,1,1,152.14834054852491+1477.8324093439965i 48 | 7,0,0,7,63090,1,1,222.42797691382899+1909.8641493261644i 49 | 7,0,0,7,93090,1,1,379.14882482319911+2736.5436896050605i 50 | 8,0,0,8,1530,1,1,1.0671251044053824+52.019337326549561i 51 | 8,0,0,8,8250,1,1,12.473955446320245+272.6373337925026i 52 | 8,0,0,8,20370,1,1,45.578137561435831+654.28089056049589i 53 | 8,0,0,8,33030,1,1,90.273016061787146+1038.5053084437895i 54 | 8,0,0,8,47970,1,1,152.14834054852491+1477.8324093439965i 55 | 8,0,0,8,63090,1,1,222.42797691382899+1909.8641493261644i 56 | 8,0,0,8,93090,1,1,379.14882482319911+2736.5436896050605i 57 | 9,0,0,9,1530,1,1,1.0671251044053824+52.019337326549561i 58 | 9,0,0,9,8250,1,1,12.473955446320245+272.6373337925026i 59 | 9,0,0,9,20370,1,1,45.578137561435831+654.28089056049589i 60 | 9,0,0,9,33030,1,1,90.273016061787146+1038.5053084437895i 61 | 9,0,0,9,47970,1,1,152.14834054852491+1477.8324093439965i 62 | 9,0,0,9,63090,1,1,222.42797691382899+1909.8641493261644i 63 | 9,0,0,9,93090,1,1,379.14882482319911+2736.5436896050605i 64 | 10,0,0,10,1530,1,1,1.0671251044053824+52.019337326549561i 65 | 10,0,0,10,8250,1,1,12.473955446320245+272.6373337925026i 66 | 10,0,0,10,20370,1,1,45.578137561435831+654.28089056049589i 67 | 10,0,0,10,33030,1,1,90.273016061787146+1038.5053084437895i 68 | 10,0,0,10,47970,1,1,152.14834054852491+1477.8324093439965i 69 | 10,0,0,10,63090,1,1,222.42797691382899+1909.8641493261644i 70 | 10,0,0,10,93090,1,1,379.14882482319911+2736.5436896050605i 71 | 11,0,0,11,1530,1,1,1.0671251044053824+52.019337326549561i 72 | 11,0,0,11,8250,1,1,12.473955446320245+272.6373337925026i 73 | 11,0,0,11,20370,1,1,45.578137561435831+654.28089056049589i 74 | 11,0,0,11,33030,1,1,90.273016061787146+1038.5053084437895i 75 | 11,0,0,11,47970,1,1,152.14834054852491+1477.8324093439965i 76 | 11,0,0,11,63090,1,1,222.42797691382899+1909.8641493261644i 77 | 11,0,0,11,93090,1,1,379.14882482319911+2736.5436896050605i 78 | 12,0,0,12,1530,1,1,1.407552340059588+60.233522798833633i 79 | 12,0,0,12,8250,1,1,18.792058293211277+314.29955618111762i 80 | 12,0,0,12,20370,1,1,72.321090984875113+746.58042382201791i 81 | 12,0,0,12,33030,1,1,144.76114787995297+1172.7051634234431i 82 | 12,0,0,12,47970,1,1,242.95785211697637+1650.007342322624i 83 | 12,0,0,12,63090,1,1,351.17591071927791+2110.4374494178792i 84 | 12,0,0,12,93090,1,1,581.27548020477502+2971.2599697725568i 85 | 13,0,0,13,1530,1,1,1.407552340059588+60.233522798833633i 86 | 13,0,0,13,8250,1,1,18.792058293211277+314.29955618111762i 87 | 13,0,0,13,20370,1,1,72.321090984875113+746.58042382201791i 88 | 13,0,0,13,33030,1,1,144.76114787995297+1172.7051634234431i 89 | 13,0,0,13,47970,1,1,242.95785211697637+1650.007342322624i 90 | 13,0,0,13,63090,1,1,351.17591071927791+2110.4374494178792i 91 | 13,0,0,13,93090,1,1,581.27548020477502+2971.2599697725568i 92 | 14,0,0,14,1530,1,1,1.407552340059588+60.233522798833633i 93 | 14,0,0,14,8250,1,1,18.792058293211277+314.29955618111762i 94 | 14,0,0,14,20370,1,1,72.321090984875113+746.58042382201791i 95 | 14,0,0,14,33030,1,1,144.76114787995297+1172.7051634234431i 96 | 14,0,0,14,47970,1,1,242.95785211697637+1650.007342322624i 97 | 14,0,0,14,63090,1,1,351.17591071927791+2110.4374494178792i 98 | 14,0,0,14,93090,1,1,581.27548020477502+2971.2599697725568i 99 | 15,0,0,15,1530,1,1,1.407552340059588+60.233522798833633i 100 | 15,0,0,15,8250,1,1,18.792058293211277+314.29955618111762i 101 | 15,0,0,15,20370,1,1,72.321090984875113+746.58042382201791i 102 | 15,0,0,15,33030,1,1,144.76114787995297+1172.7051634234431i 103 | 15,0,0,15,47970,1,1,242.95785211697637+1650.007342322624i 104 | 15,0,0,15,63090,1,1,351.17591071927791+2110.4374494178792i 105 | 15,0,0,15,93090,1,1,581.27548020477502+2971.2599697725568i 106 | 16,0,0,16,1530,1,1,1.0671251044053824+52.019337326549561i 107 | 16,0,0,16,8250,1,1,12.473955446320245+272.6373337925026i 108 | 16,0,0,16,20370,1,1,45.578137561435831+654.28089056049589i 109 | 16,0,0,16,33030,1,1,90.273016061787146+1038.5053084437895i 110 | 16,0,0,16,47970,1,1,152.14834054852491+1477.8324093439965i 111 | 16,0,0,16,63090,1,1,222.42797691382899+1909.8641493261644i 112 | 16,0,0,16,93090,1,1,379.14882482319911+2736.5436896050605i 113 | 17,0,0,17,1530,1,1,1.0671251044053824+52.019337326549561i 114 | 17,0,0,17,8250,1,1,12.473955446320245+272.6373337925026i 115 | 17,0,0,17,20370,1,1,45.578137561435831+654.28089056049589i 116 | 17,0,0,17,33030,1,1,90.273016061787146+1038.5053084437895i 117 | 17,0,0,17,47970,1,1,152.14834054852491+1477.8324093439965i 118 | 17,0,0,17,63090,1,1,222.42797691382899+1909.8641493261644i 119 | 17,0,0,17,93090,1,1,379.14882482319911+2736.5436896050605i 120 | 18,0,0,18,1530,1,1,1.0671251044053824+52.019337326549561i 121 | 18,0,0,18,8250,1,1,12.473955446320245+272.6373337925026i 122 | 18,0,0,18,20370,1,1,45.578137561435831+654.28089056049589i 123 | 18,0,0,18,33030,1,1,90.273016061787146+1038.5053084437895i 124 | 18,0,0,18,47970,1,1,152.14834054852491+1477.8324093439965i 125 | 18,0,0,18,63090,1,1,222.42797691382899+1909.8641493261644i 126 | 18,0,0,18,93090,1,1,379.14882482319911+2736.5436896050605i 127 | 19,0,0,19,1530,1,1,1.0671251044053824+52.019337326549561i 128 | 19,0,0,19,8250,1,1,12.473955446320245+272.6373337925026i 129 | 19,0,0,19,20370,1,1,45.578137561435831+654.28089056049589i 130 | 19,0,0,19,33030,1,1,90.273016061787146+1038.5053084437895i 131 | 19,0,0,19,47970,1,1,152.14834054852491+1477.8324093439965i 132 | 19,0,0,19,63090,1,1,222.42797691382899+1909.8641493261644i 133 | 19,0,0,19,93090,1,1,379.14882482319911+2736.5436896050605i 134 | 20,0,0,20,1530,1,1,1.0671251044053824+52.019337326549561i 135 | 20,0,0,20,8250,1,1,12.473955446320245+272.6373337925026i 136 | 20,0,0,20,20370,1,1,45.578137561435831+654.28089056049589i 137 | 20,0,0,20,33030,1,1,90.273016061787146+1038.5053084437895i 138 | 20,0,0,20,47970,1,1,152.14834054852491+1477.8324093439965i 139 | 20,0,0,20,63090,1,1,222.42797691382899+1909.8641493261644i 140 | 20,0,0,20,93090,1,1,379.14882482319911+2736.5436896050605i 141 | 21,0,0,21,1530,1,1,1.0671251044053824+52.019337326549561i 142 | 21,0,0,21,8250,1,1,12.473955446320245+272.6373337925026i 143 | 21,0,0,21,20370,1,1,45.578137561435831+654.28089056049589i 144 | 21,0,0,21,33030,1,1,90.273016061787146+1038.5053084437895i 145 | 21,0,0,21,47970,1,1,152.14834054852491+1477.8324093439965i 146 | 21,0,0,21,63090,1,1,222.42797691382899+1909.8641493261644i 147 | 21,0,0,21,93090,1,1,379.14882482319911+2736.5436896050605i 148 | 22,0,0,22,1530,1,1,1.0671251044053824+52.019337326549561i 149 | 22,0,0,22,8250,1,1,12.473955446320245+272.6373337925026i 150 | 22,0,0,22,20370,1,1,45.578137561435831+654.28089056049589i 151 | 22,0,0,22,33030,1,1,90.273016061787146+1038.5053084437895i 152 | 22,0,0,22,47970,1,1,152.14834054852491+1477.8324093439965i 153 | 22,0,0,22,63090,1,1,222.42797691382899+1909.8641493261644i 154 | 22,0,0,22,93090,1,1,379.14882482319911+2736.5436896050605i 155 | 23,0,0,23,1530,1,1,1.0671251044053824+52.019337326549561i 156 | 23,0,0,23,8250,1,1,12.473955446320245+272.6373337925026i 157 | 23,0,0,23,20370,1,1,45.578137561435831+654.28089056049589i 158 | 23,0,0,23,33030,1,1,90.273016061787146+1038.5053084437895i 159 | 23,0,0,23,47970,1,1,152.14834054852491+1477.8324093439965i 160 | 23,0,0,23,63090,1,1,222.42797691382899+1909.8641493261644i 161 | 23,0,0,23,93090,1,1,379.14882482319911+2736.5436896050605i 162 | 24,0,0,24,1530,1,1,1.0671251044053824+52.019337326549561i 163 | 24,0,0,24,8250,1,1,12.473955446320245+272.6373337925026i 164 | 24,0,0,24,20370,1,1,45.578137561435831+654.28089056049589i 165 | 24,0,0,24,33030,1,1,90.273016061787146+1038.5053084437895i 166 | 24,0,0,24,47970,1,1,152.14834054852491+1477.8324093439965i 167 | 24,0,0,24,63090,1,1,222.42797691382899+1909.8641493261644i 168 | 24,0,0,24,93090,1,1,379.14882482319911+2736.5436896050605i 169 | 25,0,0,25,1530,1,1,1.0671251044053824+52.019337326549561i 170 | 25,0,0,25,8250,1,1,12.473955446320245+272.6373337925026i 171 | 25,0,0,25,20370,1,1,45.578137561435831+654.28089056049589i 172 | 25,0,0,25,33030,1,1,90.273016061787146+1038.5053084437895i 173 | 25,0,0,25,47970,1,1,152.14834054852491+1477.8324093439965i 174 | 25,0,0,25,63090,1,1,222.42797691382899+1909.8641493261644i 175 | 25,0,0,25,93090,1,1,379.14882482319911+2736.5436896050605i 176 | -------------------------------------------------------------------------------- /Data-sets/Synthetic/Input_femic_initial.dat: -------------------------------------------------------------------------------- 1 | 1.00 0.00 0.00 1 1 2.0000 0.0100 0.0000 2 | 1.00 0.00 0.00 1 2 2.0000 0.0100 0.0000 3 | 1.00 0.00 0.00 1 3 2.0000 0.0100 0.0000 4 | 1.00 0.00 0.00 1 4 2.0000 0.0100 0.0000 5 | 1.00 0.00 0.00 1 5 2.0000 0.0100 0.0000 6 | 1.00 0.00 0.00 1 6 2.0000 0.0100 0.0000 7 | 1.00 0.00 0.00 1 7 2.0000 0.0100 0.0000 8 | 2.00 0.00 0.00 2 1 2.0000 0.0100 0.0000 9 | 2.00 0.00 0.00 2 2 2.0000 0.0100 0.0000 10 | 2.00 0.00 0.00 2 3 2.0000 0.0100 0.0000 11 | 2.00 0.00 0.00 2 4 2.0000 0.0100 0.0000 12 | 2.00 0.00 0.00 2 5 2.0000 0.0100 0.0000 13 | 2.00 0.00 0.00 2 6 2.0000 0.0100 0.0000 14 | 2.00 0.00 0.00 2 7 2.0000 0.0100 0.0000 15 | 3.00 0.00 0.00 3 1 2.0000 0.0100 0.0000 16 | 3.00 0.00 0.00 3 2 2.0000 0.0100 0.0000 17 | 3.00 0.00 0.00 3 3 2.0000 0.0100 0.0000 18 | 3.00 0.00 0.00 3 4 2.0000 0.0100 0.0000 19 | 3.00 0.00 0.00 3 5 2.0000 0.0100 0.0000 20 | 3.00 0.00 0.00 3 6 2.0000 0.0100 0.0000 21 | 3.00 0.00 0.00 3 7 2.0000 0.0100 0.0000 22 | 4.00 0.00 0.00 4 1 2.0000 0.0100 0.0000 23 | 4.00 0.00 0.00 4 2 2.0000 0.0100 0.0000 24 | 4.00 0.00 0.00 4 3 2.0000 0.0100 0.0000 25 | 4.00 0.00 0.00 4 4 2.0000 0.0100 0.0000 26 | 4.00 0.00 0.00 4 5 2.0000 0.0100 0.0000 27 | 4.00 0.00 0.00 4 6 2.0000 0.0100 0.0000 28 | 4.00 0.00 0.00 4 7 2.0000 0.0100 0.0000 29 | 5.00 0.00 0.00 5 1 2.0000 0.0100 0.0000 30 | 5.00 0.00 0.00 5 2 2.0000 0.0100 0.0000 31 | 5.00 0.00 0.00 5 3 2.0000 0.0100 0.0000 32 | 5.00 0.00 0.00 5 4 2.0000 0.0100 0.0000 33 | 5.00 0.00 0.00 5 5 2.0000 0.0100 0.0000 34 | 5.00 0.00 0.00 5 6 2.0000 0.0100 0.0000 35 | 5.00 0.00 0.00 5 7 2.0000 0.0100 0.0000 36 | 6.00 0.00 0.00 6 1 2.0000 0.0100 0.0000 37 | 6.00 0.00 0.00 6 2 2.0000 0.0100 0.0000 38 | 6.00 0.00 0.00 6 3 2.0000 0.0100 0.0000 39 | 6.00 0.00 0.00 6 4 2.0000 0.0100 0.0000 40 | 6.00 0.00 0.00 6 5 2.0000 0.0100 0.0000 41 | 6.00 0.00 0.00 6 6 2.0000 0.0100 0.0000 42 | 6.00 0.00 0.00 6 7 2.0000 0.0100 0.0000 43 | 7.00 0.00 0.00 7 1 2.0000 0.0100 0.0000 44 | 7.00 0.00 0.00 7 2 2.0000 0.0100 0.0000 45 | 7.00 0.00 0.00 7 3 2.0000 0.0100 0.0000 46 | 7.00 0.00 0.00 7 4 2.0000 0.0100 0.0000 47 | 7.00 0.00 0.00 7 5 2.0000 0.0100 0.0000 48 | 7.00 0.00 0.00 7 6 2.0000 0.0100 0.0000 49 | 7.00 0.00 0.00 7 7 2.0000 0.0100 0.0000 50 | 8.00 0.00 0.00 8 1 2.0000 0.0100 0.0000 51 | 8.00 0.00 0.00 8 2 2.0000 0.0100 0.0000 52 | 8.00 0.00 0.00 8 3 2.0000 0.0100 0.0000 53 | 8.00 0.00 0.00 8 4 2.0000 0.0100 0.0000 54 | 8.00 0.00 0.00 8 5 2.0000 0.0100 0.0000 55 | 8.00 0.00 0.00 8 6 2.0000 0.0100 0.0000 56 | 8.00 0.00 0.00 8 7 2.0000 0.0100 0.0000 57 | 9.00 0.00 0.00 9 1 2.0000 0.0100 0.0000 58 | 9.00 0.00 0.00 9 2 2.0000 0.0100 0.0000 59 | 9.00 0.00 0.00 9 3 2.0000 0.0100 0.0000 60 | 9.00 0.00 0.00 9 4 2.0000 0.0100 0.0000 61 | 9.00 0.00 0.00 9 5 2.0000 0.0100 0.0000 62 | 9.00 0.00 0.00 9 6 2.0000 0.0100 0.0000 63 | 9.00 0.00 0.00 9 7 2.0000 0.0100 0.0000 64 | 10.00 0.00 0.00 10 1 2.0000 0.0100 0.0000 65 | 10.00 0.00 0.00 10 2 2.0000 0.0100 0.0000 66 | 10.00 0.00 0.00 10 3 2.0000 0.0100 0.0000 67 | 10.00 0.00 0.00 10 4 2.0000 0.0100 0.0000 68 | 10.00 0.00 0.00 10 5 2.0000 0.0100 0.0000 69 | 10.00 0.00 0.00 10 6 2.0000 0.0100 0.0000 70 | 10.00 0.00 0.00 10 7 2.0000 0.0100 0.0000 71 | 11.00 0.00 0.00 11 1 2.0000 0.0100 0.0000 72 | 11.00 0.00 0.00 11 2 2.0000 0.0100 0.0000 73 | 11.00 0.00 0.00 11 3 2.0000 0.0100 0.0000 74 | 11.00 0.00 0.00 11 4 2.0000 0.0100 0.0000 75 | 11.00 0.00 0.00 11 5 2.0000 0.0100 0.0000 76 | 11.00 0.00 0.00 11 6 2.0000 0.0100 0.0000 77 | 11.00 0.00 0.00 11 7 2.0000 0.0100 0.0000 78 | 12.00 0.00 0.00 12 1 2.0000 0.0100 0.0000 79 | 12.00 0.00 0.00 12 2 2.0000 0.0100 0.0000 80 | 12.00 0.00 0.00 12 3 2.0000 0.0100 0.0000 81 | 12.00 0.00 0.00 12 4 2.0000 0.0100 0.0000 82 | 12.00 0.00 0.00 12 5 2.0000 0.0100 0.0000 83 | 12.00 0.00 0.00 12 6 2.0000 0.0100 0.0000 84 | 12.00 0.00 0.00 12 7 2.0000 0.0100 0.0000 85 | 13.00 0.00 0.00 13 1 2.0000 0.0100 0.0000 86 | 13.00 0.00 0.00 13 2 2.0000 0.0100 0.0000 87 | 13.00 0.00 0.00 13 3 2.0000 0.0100 0.0000 88 | 13.00 0.00 0.00 13 4 2.0000 0.0100 0.0000 89 | 13.00 0.00 0.00 13 5 2.0000 0.0100 0.0000 90 | 13.00 0.00 0.00 13 6 2.0000 0.0100 0.0000 91 | 13.00 0.00 0.00 13 7 2.0000 0.0100 0.0000 92 | 14.00 0.00 0.00 14 1 2.0000 0.0100 0.0000 93 | 14.00 0.00 0.00 14 2 2.0000 0.0100 0.0000 94 | 14.00 0.00 0.00 14 3 2.0000 0.0100 0.0000 95 | 14.00 0.00 0.00 14 4 2.0000 0.0100 0.0000 96 | 14.00 0.00 0.00 14 5 2.0000 0.0100 0.0000 97 | 14.00 0.00 0.00 14 6 2.0000 0.0100 0.0000 98 | 14.00 0.00 0.00 14 7 2.0000 0.0100 0.0000 99 | 15.00 0.00 0.00 15 1 2.0000 0.0100 0.0000 100 | 15.00 0.00 0.00 15 2 2.0000 0.0100 0.0000 101 | 15.00 0.00 0.00 15 3 2.0000 0.0100 0.0000 102 | 15.00 0.00 0.00 15 4 2.0000 0.0100 0.0000 103 | 15.00 0.00 0.00 15 5 2.0000 0.0100 0.0000 104 | 15.00 0.00 0.00 15 6 2.0000 0.0100 0.0000 105 | 15.00 0.00 0.00 15 7 2.0000 0.0100 0.0000 106 | 16.00 0.00 0.00 16 1 2.0000 0.0100 0.0000 107 | 16.00 0.00 0.00 16 2 2.0000 0.0100 0.0000 108 | 16.00 0.00 0.00 16 3 2.0000 0.0100 0.0000 109 | 16.00 0.00 0.00 16 4 2.0000 0.0100 0.0000 110 | 16.00 0.00 0.00 16 5 2.0000 0.0100 0.0000 111 | 16.00 0.00 0.00 16 6 2.0000 0.0100 0.0000 112 | 16.00 0.00 0.00 16 7 2.0000 0.0100 0.0000 113 | 17.00 0.00 0.00 17 1 2.0000 0.0100 0.0000 114 | 17.00 0.00 0.00 17 2 2.0000 0.0100 0.0000 115 | 17.00 0.00 0.00 17 3 2.0000 0.0100 0.0000 116 | 17.00 0.00 0.00 17 4 2.0000 0.0100 0.0000 117 | 17.00 0.00 0.00 17 5 2.0000 0.0100 0.0000 118 | 17.00 0.00 0.00 17 6 2.0000 0.0100 0.0000 119 | 17.00 0.00 0.00 17 7 2.0000 0.0100 0.0000 120 | 18.00 0.00 0.00 18 1 2.0000 0.0100 0.0000 121 | 18.00 0.00 0.00 18 2 2.0000 0.0100 0.0000 122 | 18.00 0.00 0.00 18 3 2.0000 0.0100 0.0000 123 | 18.00 0.00 0.00 18 4 2.0000 0.0100 0.0000 124 | 18.00 0.00 0.00 18 5 2.0000 0.0100 0.0000 125 | 18.00 0.00 0.00 18 6 2.0000 0.0100 0.0000 126 | 18.00 0.00 0.00 18 7 2.0000 0.0100 0.0000 127 | 19.00 0.00 0.00 19 1 2.0000 0.0100 0.0000 128 | 19.00 0.00 0.00 19 2 2.0000 0.0100 0.0000 129 | 19.00 0.00 0.00 19 3 2.0000 0.0100 0.0000 130 | 19.00 0.00 0.00 19 4 2.0000 0.0100 0.0000 131 | 19.00 0.00 0.00 19 5 2.0000 0.0100 0.0000 132 | 19.00 0.00 0.00 19 6 2.0000 0.0100 0.0000 133 | 19.00 0.00 0.00 19 7 2.0000 0.0100 0.0000 134 | 20.00 0.00 0.00 20 1 2.0000 0.0100 0.0000 135 | 20.00 0.00 0.00 20 2 2.0000 0.0100 0.0000 136 | 20.00 0.00 0.00 20 3 2.0000 0.0100 0.0000 137 | 20.00 0.00 0.00 20 4 2.0000 0.0100 0.0000 138 | 20.00 0.00 0.00 20 5 2.0000 0.0100 0.0000 139 | 20.00 0.00 0.00 20 6 2.0000 0.0100 0.0000 140 | 20.00 0.00 0.00 20 7 2.0000 0.0100 0.0000 141 | 21.00 0.00 0.00 21 1 2.0000 0.0100 0.0000 142 | 21.00 0.00 0.00 21 2 2.0000 0.0100 0.0000 143 | 21.00 0.00 0.00 21 3 2.0000 0.0100 0.0000 144 | 21.00 0.00 0.00 21 4 2.0000 0.0100 0.0000 145 | 21.00 0.00 0.00 21 5 2.0000 0.0100 0.0000 146 | 21.00 0.00 0.00 21 6 2.0000 0.0100 0.0000 147 | 21.00 0.00 0.00 21 7 2.0000 0.0100 0.0000 148 | 22.00 0.00 0.00 22 1 2.0000 0.0100 0.0000 149 | 22.00 0.00 0.00 22 2 2.0000 0.0100 0.0000 150 | 22.00 0.00 0.00 22 3 2.0000 0.0100 0.0000 151 | 22.00 0.00 0.00 22 4 2.0000 0.0100 0.0000 152 | 22.00 0.00 0.00 22 5 2.0000 0.0100 0.0000 153 | 22.00 0.00 0.00 22 6 2.0000 0.0100 0.0000 154 | 22.00 0.00 0.00 22 7 2.0000 0.0100 0.0000 155 | 23.00 0.00 0.00 23 1 2.0000 0.0100 0.0000 156 | 23.00 0.00 0.00 23 2 2.0000 0.0100 0.0000 157 | 23.00 0.00 0.00 23 3 2.0000 0.0100 0.0000 158 | 23.00 0.00 0.00 23 4 2.0000 0.0100 0.0000 159 | 23.00 0.00 0.00 23 5 2.0000 0.0100 0.0000 160 | 23.00 0.00 0.00 23 6 2.0000 0.0100 0.0000 161 | 23.00 0.00 0.00 23 7 2.0000 0.0100 0.0000 162 | 24.00 0.00 0.00 24 1 2.0000 0.0100 0.0000 163 | 24.00 0.00 0.00 24 2 2.0000 0.0100 0.0000 164 | 24.00 0.00 0.00 24 3 2.0000 0.0100 0.0000 165 | 24.00 0.00 0.00 24 4 2.0000 0.0100 0.0000 166 | 24.00 0.00 0.00 24 5 2.0000 0.0100 0.0000 167 | 24.00 0.00 0.00 24 6 2.0000 0.0100 0.0000 168 | 24.00 0.00 0.00 24 7 2.0000 0.0100 0.0000 169 | 25.00 0.00 0.00 25 1 2.0000 0.0100 0.0000 170 | 25.00 0.00 0.00 25 2 2.0000 0.0100 0.0000 171 | 25.00 0.00 0.00 25 3 2.0000 0.0100 0.0000 172 | 25.00 0.00 0.00 25 4 2.0000 0.0100 0.0000 173 | 25.00 0.00 0.00 25 5 2.0000 0.0100 0.0000 174 | 25.00 0.00 0.00 25 6 2.0000 0.0100 0.0000 175 | 25.00 0.00 0.00 25 7 2.0000 0.0100 0.0000 176 | -------------------------------------------------------------------------------- /Data-sets/Synthetic/READ ME.txt: -------------------------------------------------------------------------------- 1 | The Synthetic Example folder contains this READ ME file and four additional files: 2 | 3 | 1) Input_femic.dat: A text (ascii) file containing the input data, with columns of: 4 | - x location in meters 5 | - y location in meters 6 | - z location in meters 7 | - sounding identification (ID) #, with different data at same location sharing a sounding ID 8 | - frequency, in hertz 9 | - Standard error, in data units 10 | - coil configration, 1 for vertical dipole, 2 for horizontal dipole, or 3 for both 11 | - list of apparent conductivity values for each frequency, in milliSiemens/meter 12 | 13 | 14 | 2) Input_femic_initial.dat: A text (ascii) file containing initial FEMIC models for this example, with columns of: 15 | - x location in meters 16 | - y location in meters 17 | - z location in meters 18 | - sounding identification 19 | - layer number 20 | - initial conductivity value, in milliSiemens/meter for each layer 21 | - additional rows for alternative starting models 22 | 23 | 3) Real_model.tif: A TIF image file containing the true, synthetic conductivity structure 24 | 25 | 4) TEST.tif: A file containing a TIF image of the inversion results for this example 26 | 27 | -------------------------------------------------------------------------------- /Data-sets/Synthetic/Real_model.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Data-sets/Synthetic/Real_model.tif -------------------------------------------------------------------------------- /Data-sets/Synthetic/TEST.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Data-sets/Synthetic/TEST.tif -------------------------------------------------------------------------------- /Data-sets/Synthetic/data: -------------------------------------------------------------------------------- 1 | data 2 | -------------------------------------------------------------------------------- /Figure11/Figure 11.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elwaseif/FEMIC-Code/f7413068c5533743ab83c97074702dd06a877056/Figure11/Figure 11.kmz -------------------------------------------------------------------------------- /Figure11/KMZ: -------------------------------------------------------------------------------- 1 | KMZ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FEMIC-Code 2 | Supplemental for Computer & Geoscience paper entitled "A Matlab-Based Frequency-Domain Electromagnetic Inversion Code (FEMIC) with Graphical User Interface" 3 | 4 | This folder contains three sub folders, one for the FEMIC code ('Code'), the second for the datasets ('datasets'), and the third for Figure 11 ('Figure 11') used in the paper: 5 | 6 | - Code: This folder contains the matlab functions to run the code.The FEMIC code can be installed by placing the Code folder where 7 | accessible via Matlab, opening Matlab, changing the workspace to the Code folder and typing 'start' at the Matlab prompt. A brief user manual 8 | is provided in this folder as a pdf. 9 | 10 | - Datasets: This folder contains the datasets used in the paper. 11 | 12 | - Figure 11: This folder contains KMZ file to visualize Figure 11 on Google Earth application. 13 | --------------------------------------------------------------------------------