The method of characteristics for two dimensional advection equation - matlab

Given the following function to solve the two-dimensional advection equation in a rectangle:
function qnew = SemiLagrAdvect(u,v,q,qS,qN,qW,qE)
global N M
global dx dy
global dt Re
u = reshape(u,N,M);
v = reshape(v,N,M);
q = reshape(q,N,M);
%...embedding
qq = zeros(N+2,M+2);
qq(2:N+1,2:M+1) = q;
%...set the ghost values (four edges)
qq(1,2:M+1) = 2*qW-qq(2,2:M+1);
qq(N+2,2:M+1) = 2*qE-qq(N+1,2:M+1);
qq(2:N+1,1) = 2*qS-qq(2:N+1,2);
qq(2:N+1,M+2) = 2*qN-qq(2:N+1,M+1);
%...set the ghost values (four corners)
qq(1,1) = -qq(2,2);
qq(N+2,1) = -qq(N+1,2);
qq(N+2,M+2) = -qq(N+1,M+1);
qq(1,M+2) = -qq(2,M+1);
q1 = qq(2:N+1,2:M+1);
q2p = qq(3:N+2,2:M+1);
q2m = qq(1:N,2:M+1);
q3p = qq(2:N+1,3:M+2);
q3m = qq(2:N+1,1:M);
q4pp = qq(3:N+2,3:M+2);
q4mm = qq(1:N,1:M);
q4pm = qq(3:N+2,1:M);
q4mp = qq(1:N,3:M+2);
xi = -u*dt/dx;
eta = -v*dt/dy;
Q2 = q2p.*(xi>0) + q2m.*(xi<0);
Q3 = q3p.*(eta>0) + q3m.*(eta<0);
Q4 = q4pp.*((xi>0) & (eta>0)) + q4mm.*((xi<0) & (eta<0)) + ...
q4pm.*((xi>0) & (eta<0)) + q4mp.*((xi<0) & (eta>0));
qnew = (1-abs(xi)).*(1-abs(eta)).*q1 + ...
abs(xi).*(1-abs(eta)).*Q2 + ...
abs(eta).*(1-abs(xi)).*Q3 + ...
abs(xi).*abs(eta).*Q4;
qnew = qnew(:);
Having elementary knowledge in MATLAB, how can I modify it to solve the equation in a composite domain?

you need to use continuity on the interface.Depending on your method.
In the method of characteristics the interface is part of the initial curve.
S
I'm

Related

Optimal control of Euler equations of gas dynamics in Matlab

I am trying to solve the optimal control for the Euler equations of gas dynamics with the cost functional of the tracking type function. The idea is optimal solutions must match the target solutions at a final time by updating the control function using the steepest descent method. I have done the program using Matlab, but the result doesn't achieve the goal; I have attached the part of the code where the issue is. The problem is mainly with the optimization loop. Any help or advice will be appreciated.
alphaAD0 = 2.9*[1,1,1]; % optim step for adjoint
ObjwAD = costfunction(rho,m,E,rhod,md,Ed,par);
for iter = 2:maxIter
alphaAD = alphaAD0;
rhoinv = rhoT(end:-1:1,:);
minv = mT(end:-1:1,:);
Einv = ET(end:-1:1,:);
[p,q] = initbackward(rho,m,E,rhod,md,Ed,par);
[pp,qq] = backwardsolve(p,q,rhoinv,minv,Einv,par);
[ADgradJrho0,ADgradJm0,ADgradJE0] = qradcost(pp,qq,rho0,m0,E0,par);
% Update data
rho00 = rho0 - alphaAD(1)*ADgradJrho0;
m00 = m0 - alphaAD(2)*ADgradJm0;
E00 = E0 - alphaAD(3)*ADgradJE0;
[rhoT,mT,ET] = forwardsolve(rho00,m00,E00,par);
rho = rhoT(end,:);
m = mT(end,:);
E = ET(end,:);
u = m./rho;
p = (par.G - 1)*(E - 0.5*rho.*u.^2);
Objfunc_1 = ObjwAD(iter-1);
Objfunc = costfunction(rho,m,E,rhod,md,Ed,par);
while Objfunc>Objfunc_1 || isnan(Objfunc)
alphaAD = alphaAD/2;
rho00 = rho0 - alphaAD(1)*ADgradJrho0;
m00 = m0 - alphaAD(2)*ADgradJm0;
E00 = E0 - alphaAD(3)*ADgradJE0;
[rhoT,mT,ET] = forwardsolve(rho00,m00,E00,par);
rho = rhoT(end,:);
m = mT(end,:);
E = ET(end,:);
u = m./rho;
p = (par.G - 1)*(E - 0.5*rho.*u.^2);
Objfunc = costfunction(rho,m,E,rhod,md,Ed,par);
end
rho0 = rho00; m0 = m00; E0 = E00;

Creating a table from a variable inside a for loop

I am writing a for loop to calculate the value of four different variables. The first variable is M. M increases from 10^2 to 10^5,
M = [10^2,10^3,10^4,10^5];
The other three variables needed for the table are shown in the code below.
confmc
confcv
confmcSize/confcvSize
I first create a for loop to iterate through the four different values of M. I then create the table outside of the for loop.
How could I adjust the implementation so that the table displays all four values of M?
randn('state',100)
%%%%%% Problem and method parameters %%%%%%%%%
S = 5; E = 6; sigma = 0.3; r = 0.05; T = 1;
Dt = 1e-2; N = T/Dt; M = [10^2,10^3,10^4,10^5];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for k=1:numel(M)
%%%%%%%%% Geom Asian exact mean %%%%%%%%%%%%
sigsqT= sigma^2*T*(N+1)*(2*N+1)/(6*N*N);
muT = 0.5*sigsqT + (r - 0.5*sigma^2)*T*(N+1)/(2*N);
d1 = (log(S/E) + (muT + 0.5*sigsqT))/(sqrt(sigsqT));
d2 = d1 - sqrt(sigsqT);
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
geo = exp(-r*T)*( S*exp(muT)*N1 - E*N2 );
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Spath = S*cumprod(exp((r-0.5*sigma^2)*Dt+sigma*sqrt(Dt)*randn(M(k),N)),2);
% Standard Monte Carlo
arithave = mean(Spath,2);
Parith = exp(-r*T)*max(arithave-E,0); % payoffs
Pmean = mean(Parith);
Pstd = std(Parith);
confmc = [Pmean-1.96*Pstd/sqrt(M(k)), Pmean+1.96*Pstd/sqrt(M(k))];
confmcSize = [(Pmean+1.96*Pstd/sqrt(M(k)))-(Pmean-1.96*Pstd/sqrt(M(k)))];
% Control Variate
geoave = exp((1/N)*sum(log(Spath),2));
Pgeo = exp(-r*T)*max(geoave-E,0); % geo payoffs
Z = Parith + geo - Pgeo; % control variate version
Zmean = mean(Z);
Zstd = std(Z);
confcv = [Zmean-1.96*Zstd/sqrt(M(k)), Zmean+1.96*Zstd/sqrt(M(k))];
confcvSize = [(Zmean+1.96*Zstd/sqrt(M(k)))-(Zmean-1.96*Zstd/sqrt(M(k)))];
end
T = table(M,confmc,confcv,confmcSize/confcvSize)
The current code returns
T =
1×4 table
M confmc confcv Var4
_____ ____________________ ____________________ ______
1e+05 0.096756 0.1007 0.097306 0.097789 8.1622
How could I change my implementation so that all four values of M are computed?
I just modified few things.Take a look at the following code.
randn('state',100)
%%%%%% Problem and method parameters %%%%%%%%%
S = 5; E = 6; sigma = 0.3; r = 0.05; T = 1;
Dt = 1e-2; N = T/Dt; M = [10^2,10^3,10^4,10^5];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
confmc = zeros(numel(M), 2);
confcv = zeros(numel(M), 2);
confmcSize = zeros(numel(M), 1);
confcvSize = zeros(numel(M), 1);
for k=1:numel(M)
%%%%%%%%% Geom Asian exact mean %%%%%%%%%%%%
sigsqT= sigma^2*T*(N+1)*(2*N+1)/(6*N*N);
muT = 0.5*sigsqT + (r - 0.5*sigma^2)*T*(N+1)/(2*N);
d1 = (log(S/E) + (muT + 0.5*sigsqT))/(sqrt(sigsqT));
d2 = d1 - sqrt(sigsqT);
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
geo = exp(-r*T)*( S*exp(muT)*N1 - E*N2 );
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Spath = S*cumprod(exp((r-0.5*sigma^2)*Dt+sigma*sqrt(Dt)*randn(M(k),N)),2);
% Standard Monte Carlo
arithave = mean(Spath,2);
Parith = exp(-r*T)*max(arithave-E,0); % payoffs
Pmean = mean(Parith);
Pstd = std(Parith);
confmc(k,:) = [Pmean-1.96*Pstd/sqrt(M(k)), Pmean+1.96*Pstd/sqrt(M(k))];
confmcSize(k,1) = [(Pmean+1.96*Pstd/sqrt(M(k)))-(Pmean-1.96*Pstd/sqrt(M(k)))];
% Control Variate
geoave = exp((1/N)*sum(log(Spath),2));
Pgeo = exp(-r*T)*max(geoave-E,0); % geo payoffs
Z = Parith + geo - Pgeo; % control variate version
Zmean = mean(Z);
Zstd = std(Z);
confcv(k,:) = [Zmean-1.96*Zstd/sqrt(M(k)), Zmean+1.96*Zstd/sqrt(M(k))];
confcvSize(k,1) = [(Zmean+1.96*Zstd/sqrt(M(k)))-(Zmean-1.96*Zstd/sqrt(M(k)))];
end
T = table(M',confmc,confcv,confmcSize./confcvSize)
In short, I just used a matrix instead of a vector or scalar as the members of the table. In your code, the variables (confmc, confcv, confmcSize, confcvSize) were getting overwritten.

Numerical Integration by Simpsons method

I am trying to solve this integration by simpsons method and plot the result in a figure.The figure is taking only the value of P0= -6 from the for loop. When I set I(K,P) it gives the error:
Attempted to access P0(0); index must be a positive integer or logical
How can I solve it?
alpha = 45;
beta = 185;
gamma_e = 116;
% Gain values
G_ei = -18.96;
G_ee = 18.52;
G_sr = -0.26;
G_rs = 16.92;
G_es = 2.55;
G_re = 4.67;
G_se = 0.73;
G_sn = 2.78;
G_esre = G_es*G_sr*G_re;
G_srs = G_sr*G_rs;
G_ese = G_es*G_se;
G_esn = G_es*G_sn;
t_0 = 0.085; % corticothalamic loop delay in second
r_e = 0.086; % Excitatory axon range in metre
f = linspace(-40,40,500); % f = frequency in Hz
w = 2*pi*f; % angular frequency in radian per second
delt_P = 0.5;
L=zeros(1,500);
Q=repmat(L,1);
P=repmat(L,1);
%%%%%%%%%%%%% integration %%%%%%%%%%%%
a = -80*pi;
b = 80*pi;
n=500;
I=repmat(L,1);
P_initial = repmat(L,1);
P_shift = repmat(L,1);
p = repmat(L,1);
for k = 1:length(w)
for P0 = [6 -6]
L_initial = #(w1) (1-((1i*w1)/alpha))^(-1)*(1-((1i*w1)/beta))^(-1);
Q_initial = #(w1) (1/(r_e^2))*((1-((1i*w1)/gamma_e))^(2) - (1/(1-G_ei*L_initial(w1)))*....
(L_initial(w1)*G_ee + (exp(1i*w1*t_0)*(L_initial(w1)^2*G_ese +L_initial(w1)^3*G_esre))/(1-L_initial(w1)^2*G_srs)));
P_initial = #(w1) (pi/r_e^4)* (abs((L_initial(w1)^2*G_esn)/((1-L_initial(w1)^2*G_srs)*....
(1-G_ei*L_initial(w1)))))^2 * abs((atan2((imag(Q_initial(w1))),(real(Q_initial(w1)))))/imag(Q_initial(w1)));
G = 150*exp(- (f - P0).^2./(2*(delt_P).^2));
P2 = #(w1) G(k) + P_initial(w1);
L_shift = #(w1) (1-((1i*(w(k)-w1))/alpha))^(-1)* (1-((1i*(w(k)-w1))/beta))^(-1);
Q_shift = #(w1) (1/(r_e^2))*((1-((1i*(w(k)-w1))/gamma_e))^(2) - (1/(1-G_ei*L_shift(w1)))*...
(L_shift(w1)*G_ee + (exp(1i*(w(k)-w1)*t_0)*(L_shift(w1)^2*G_ese +L_shift(w1)^3*G_esre))/(1-L_shift(w1)^2*G_srs)));
P_shift = #(w1) (pi/r_e^4)* (abs((L_shift(w1)^2*G_esn)/((1-L_shift(w1)^2*G_srs)*(1-G_ei*L_shift(w1)))))^2 *....
abs((atan2((imag(Q_shift(w1))),(real(Q_shift(w1)))))/imag(Q_shift(w1)));
p = #(w1) P2(w1)*P_shift(w1); % Power spectrum formula for P(w1)*p(w-w1)
I(k) = simprl(p,a,b,n);
end
end
figure(1)
plot(f,I,'r--')
figure(2)
plot(f,G,'k')
At the moment you only use the results for P0 = -6 as you save them in I(k). First you save the result for P0 = 6 later you overwrite it and save the other. The results of P0 = 6are neither used nor saved. If you write your code as follows this will be clarifyied.
for k = 1:length(w)
L_shift = #(w1) (1-((1i*(w(k)-w1))/alpha))^(-1)* (1-((1i*(w(k)-w1))/beta))^(-1);
Q_shift = #(w1) (1/(r_e^2))*((1-((1i*(w(k)-w1))/gamma_e))^(2) - (1/(1-G_ei*L_shift(w1)))*...
(L_shift(w1)*G_ee + (exp(1i*(w(k)-w1)*t_0)*(L_shift(w1)^2*G_ese +L_shift(w1)^3*G_esre))/(1-L_shift(w1)^2*G_srs)));
P_shift = #(w1) (pi/r_e^4)* (abs((L_shift(w1)^2*G_esn)/((1-L_shift(w1)^2*G_srs)*(1-G_ei*L_shift(w1)))))^2 *....
abs((atan2((imag(Q_shift(w1))),(real(Q_shift(w1)))))/imag(Q_shift(w1)));
for P0 = [6 -6]
G = 150*exp(- (f - P0).^2./(2*(delt_P).^2));
P2 = #(w1) G(k) + P_initial(w1);
p = #(w1) P2(w1)*P_shift(w1);
I(k) = simprl(p,a,b,n);
end
end
You can't access I(k,P) as I is an vector not an matrix. However this will give you Index exceeds matrix dimensions. You could save the results for P0 = -6 in one variable and P0 = 6 in the other variable as the results in your code do not depent on each other.

MATLAB - Adaptive Step Size Runge-Kutta

I've programmed in MATLAB an adaptive step size RK4 to solve a system of ODEs. The code runs without error, however it does not produce the desired curve when I try to plot x against y. Instead of being a toroidal shape, I simply get a flat line. This is evident from the fact that r is outputting a constant value. After checking the outputs of each line, they are not outputting constants or errors or inf or NaN, rather they are outputting both a real and imaginary component (complex numbers). I have no idea as to why this is occurring and I believe it to be the source of my trouble.
function AdaptRK4()
parsec = 3.08*10^18;
r_1 = 8.5*1000.0*parsec; % in cm
theta_1 = 0.0;
a = 0.5*r_1;
gam = 1;
grav = 6.6720*10^-8;
amsun = 1.989*10^33;
amg = 1.5d11*amsun;
gm = grav*amg;
u_1 = 20.0*10^5;
v = sqrt(gm/r_1);
time = 0.0;
epsilon = 0.00001;
m1 = 0.5;
m2 = 0.5;
m3 = 0.5;
i = 1;
nsteps = 50000;
deltat = 5.0*10^12;
angmom = r_1*v;
angmom2 = angmom^2.0;
e = -2*10^5.0*gm/r_1+u_1*u_1/2.0+angmom2/(2.0*r_1*r_1);
for i=1:nsteps
deltat = min(deltat,nsteps-time);
fk3_1 = deltat*u_1;
fk4_1 = deltat*(-gm*r_1*r_1^(-gam)/(a+r_1)^(3- gam)+angmom2/(r_1^3.0));
fk5_1 = deltat*(angmom/(r_1^2.0));
r_2 = r_1+fk3_1/4.0;
u_2 = u_1+fk4_1/4.0;
theta_2 = theta_1+fk5_1/4.0;
fk3_2 = deltat*u_2;
fk4_2 = deltat*(-gm*r_2*r_2^(-gam)/(a+r_2)^(3-gam)+angmom2/(r_2^3.0));
fk5_2 = deltat*(angmom/(r_2^2.0));
r_3 = r_1+(3/32)*fk3_1 + (9/32)*fk3_2;
u_3 = u_1+(3/32)*fk4_1 + (9/32)*fk4_2;
theta_3 = theta_1+(3/32)*fk5_1 + (9/32)*fk5_2;
fk3_3 = deltat*u_3;
fk4_3 = deltat*(-gm*r_3*r_3^(-gam)/(a+r_3)^(3-gam)+angmom2/(r_3^3.0));
fk5_3 = deltat*(angmom/(r_3^2.0));
r_4 = r_1+(1932/2197)*fk3_1 - (7200/2197)*fk3_2 + (7296/2197)*fk3_3;
u_4 = u_1+(1932/2197)*fk4_1 - (7200/2197)*fk4_2 + (7296/2197)*fk4_3;
theta_4 = theta_1+(1932/2197)*fk5_1 - (7200/2197)*fk5_2 + (7296/2197)*fk5_3;
fk3_4 = deltat*u_4;
fk4_4 = deltat*(-gm*r_4*r_4^(-gam)/(a+r_4)^(3-gam)+angmom2/(r_4^3.0));
fk5_4 = deltat*(angmom/(r_4^2.0));
r_5 = r_1+(439/216)*fk3_1 - 8*fk3_2 + (3680/513)*fk3_3 - (845/4104)*fk3_4;
u_5 = u_1+(439/216)*fk4_1 - 8*fk4_2 + (3680/513)*fk4_3 - (845/4104)*fk4_4;
theta_5 = theta_1+(439/216)*fk5_1 - 8*fk5_2 + (3680/513)*fk5_3 - (845/4104)*fk5_4;
fk3_5 = deltat*u_5;
fk4_5 = deltat*(-gm*r_5*r_5^(-gam)/(a+r_5)^(3-gam)+angmom2/(r_5^3.0));
fk5_5 = deltat*(angmom/(r_5^2.0));
r_6 = r_1-(8/27)*fk3_1 - 2*fk3_2 - (3544/2565)*fk3_3 + (1859/4104)*fk3_4-(11/40)*fk3_5;
u_6 = u_1-(8/27)*fk4_1 - 2*fk4_2 - (3544/2565)*fk4_3 + (1859/4104)*fk4_4-(11/40)*fk4_5;
theta_6 = theta_1-(8/27)*fk5_1 - 2*fk5_2 - (3544/2565)*fk5_3 + (1859/4104)*fk5_4-(11/40)*fk5_5;
fk3_6 = deltat*u_6;
fk4_6 = deltat*(-gm*r_6*r_6^(-gam)/(a+r_6)^(3-gam)+angmom2/(r_6^3.0));
fk5_6 = deltat*(angmom/(r_6^2.0));
fm3_1 = m1 + 25*fk3_1/216+1408*fk3_3/2565+2197*fk3_4/4104-fk3_5/5;
fm4_1 = m2 + 25*fk4_1/216+1408*fk4_3/2565+2197*fk4_4/4104-fk4_5/5;
fm5_1 = m3 + 25*fk5_1/216+1408*fk5_3/2565+2197*fk5_4/4104-fk5_5/5;
fm3_2 = m1 + 16*fk3_1/135+6656*fk3_3/12825+28561*fk3_4/56430-9*fk3_5/50+2*fk3_6/55;
fm4_2 = m2 + 16*fk4_1/135+6656*fk4_3/12825+28561*fk4_4/56430-9*fk4_5/50+2*fk4_6/55;
fm5_2 = m3 + 16*fk5_1/135+6656*fk5_3/12825+28561*fk5_4/56430-9*fk5_5/50+2*fk5_6/55;
R3 = abs(fm3_1-fm3_2)/deltat;
R4 = abs(fm4_1-fm4_2)/deltat;
R5 = abs(fm5_1-fm5_2)/deltat;
err3 = 0.84*(epsilon/R3)^(1/4);
err4 = 0.84*(epsilon/R4)^(1/4);
err5 = 0.84*(epsilon/R5)^(1/4);
if R3<= epsilon
time = time+deltat;
fm3 = fm3_1;
i = i+1;
deltat = err3*deltat;
end
if R4<= epsilon
time = time+deltat;
fm4 = fm4_1;
i = i+1;
deltat = err4*deltat;
end
if R5<= epsilon
time = time+deltat;
fm5 = fm5_1;
i = i+1;
deltat = err5*deltat;
end
e=2*gm^2.0/(2*angmom2);
ecc=(1.0+(2.0*e*angmom2)/(gm^2.0))^0.5;
x(i)=r_1*cos(theta_1)/(1000.0*parsec);
y(i)=r_1*sin(theta_1)/(1000.0*parsec);
time=time+deltat;
r(i)=r_1;
time1(i)=time;
end
figure()
plot(x,y, '-k');
TeXString = title('Plot of Orbit in Gamma Potential Obtained Using RK4')
xlabel('x')
ylabel('y')
You are getting complex values because at some point npts - time < 0. You may want to print out the values of deltat to check the error.
Also, your code doesn't seem to take into account the case when the error estimate is larger than your tolerance. When your error estimate is greater than your tolerance you have to:
Shift back the time AND solution
calculate a new step-size based on a formula, and
recalculate your solution and error estimate.
The fact that you don't know how many iterations you will have to go through makes the use of a for-loop for adaptive runge Kutta a bit awkward. I suggest using a while loop instead.
You are using "i" in your code. "i" returns the basic imaginary unit. "i" is equivalent to sqrt(-1). Try to use another identifier in your loops and only use "i" or "j" in calculations where complex numbers are involved.

speed up code - vectorization

I'm not really familiar with vectorization, but I am aware that, amongst MATLAB's strengths, code vectorization is probably the most rewarded.
I have this code:
ikx= (-Nx/2:Nx/2-1)*dk1;
iky= (-Ny/2:Ny/2-1)*dk2;
ikz= (-Nz/2:Nz/2-1)*dk3;
[k1,k2,k3] = ndgrid(ikx,iky,ikz);
k = sqrt(k1.^2 + k2.^2 + k3.^2);
Cij = zeros(3,3,Nx,Ny,Nz);
count = 0;
for ii = 1:Nx
for jj = 1:Ny
for kk = 1:Nz
if ~isequal(k1(ii,jj,kk),0)
count = count +1;
fprintf('iteration step %i\r\n',count)
E_int = interp1(k_vec,E_vec,k(ii,jj,kk),'spline','extrap');
beta = c*gamma./(k(ii,jj,kk).*sqrt(E_int));
k30 = k3(ii,jj,kk) + beta*k1(ii,jj,kk);
k0 = sqrt(k1(ii,jj,kk)^2 + k2(ii,jj,kk)^2 + k30^2);
Ek0 = 1.453*(k0^4/((1 + k0^2)^(17/6)));
B = sigmaiso*sqrt((Ek0./(k0.^2))*((dk1*dk2*dk3)/(4*pi)));
C1 = ((beta.*k1(ii,jj,kk).^2).*(k0.^2 - 2*k30.^2 + k30.*beta.*k1(ii,jj,kk)))./(k(ii,jj,kk).^2.*(k1(ii,jj,kk).^2 + k2(ii,jj,kk).^2));
C2 = ((k2(ii,jj,kk).*(k0.^2))./((k1(ii,jj,kk).^2 + k2(ii,jj,kk).^2).^(3/2))).*atan2((beta.*k1(ii,jj,kk).*sqrt(k1(ii,jj,kk).^2 + k2(ii,jj,kk).^2)),(k0.^2 - k30.*beta.*k1(ii,jj,kk)));
xhsi1 = C1 - C2.*(k2(ii,jj,kk)./k1(ii,jj,kk));
xhsi2 = C1.*(k2(ii,jj,kk)./k1(ii,jj,kk)) + C2;
Cij(1,1,ii,jj,kk) = B.*((k2(ii,jj,kk).*xhsi1)./(k0));
Cij(1,2,ii,jj,kk) = B.*((k3(ii,jj,kk)-k1(ii,jj,kk).*xhsi1+beta.*k1(ii,jj,kk))./(k0));
Cij(1,3,ii,jj,kk) = B.*(-k2(ii,jj,kk)./(k0));
Cij(2,1,ii,jj,kk) = B.*((k2(ii,jj,kk).*xhsi2-k3(ii,jj,kk)-beta.*k1(ii,jj,kk))./(k0));
Cij(2,2,ii,jj,kk) = B.*((-k1(ii,jj,kk).*xhsi2)./(k0));
Cij(2,3,ii,jj,kk) = B.*(k1(ii,jj,kk)./(k0));
Cij(3,1,ii,jj,kk) = B.*(k2(ii,jj,kk).*k0./(k(ii,jj,kk).^2));
Cij(3,2,ii,jj,kk) = B.*(-k1(ii,jj,kk).*k0./(k(ii,jj,kk).^2));
end
end
end
end
Generally, I might avoid the nested for loops; nonetheless, the if statement on k1 values is currently directing me towards the classical and old-fashion code structure.
I blatantly would like to bypass the presence of the for loops in favour of vectorized and more elegant solution.
Any support is more than welcome.
EDIT
To let better understand what the code is expected to perform, I hereby provide you with some basics:
EDIT2
As #Floris advised, I came up with this alternative solution:
ikx= (-Nx/2:Nx/2-1)*dk1;
iky= (-Ny/2:Ny/2-1)*dk2;
ikz= (-Nz/2:Nz/2-1)*dk3;
[k1,k2,k3] = ndgrid(ikx,iky,ikz);
k = sqrt(k1.^2 + k2.^2 + k3.^2);
ii = (ikx ~= 0);
k1w = k1(ii,:,:);
k2w = k2(ii,:,:);
k3w = k3(ii,:,:);
kw = k(ii,:,:);
E_int = interp1(k_vec,E_vec,kw,'spline','extrap');
beta = c*gamma./(kw.*sqrt(E_int));
k30 = k3w + beta.*k1w;
k0 = sqrt(k1w.^2 + k2w.^2 + k30.^2);
Ek0 = (1.453*k0.^4)./((1 + k0.^2).^(17/6));
B = sqrt((2*(pi^2)*(l^3))*(Ek0./(V*k0.^4)));
k1w_2 = k1w.^2;
k2w_2 = k2w.^2;
k30_2 = k30.^2;
k0_2 = k0.^2;
kw_2 = kw.^2;
C1 = ((beta.*k1w_2).*(k0_2 - 2.*k30_2 + beta.*k1w.*k30))./(kw_2.*(k1w_2 + k2w_2));
C2 = ((k2w.*k0_2)./((k1w_2 + k2w_2).^(3/2))).*atan2((beta.*k1w).*sqrt(k1w_2 + k2w_2),(k0_2 - k30.*k1w.*beta));
xhsi1 = C1 - (k2w./k1w).*C2;
xhsi2 = (k2w./k1w).*C1 + C2;
Cij = zeros(3,3,Nx,Ny,Nz);
Cij(1,1,ii,:,:) = B.*(k2w.*xhsi1);
Cij(1,2,ii,:,:) = B.*(k3w - k1w.*xhsi1 + beta.*k1w);
Cij(1,3,ii,:,:) = B.*(-k2w);
Cij(2,1,ii,:,:) = B.*(k2w.*xhsi2 - k3w - beta.*k1w);
Cij(2,2,ii,:,:) = B.*(-k1w.*xhsi2);
Cij(2,3,ii,:,:) = B.*(k1w);
Cij(3,1,ii,:,:) = B.*((k0_2./kw_2).*k2w);
Cij(3,2,ii,:,:) = B.*(-(k0_2./kw_2).*k1w);
You can do your test just once, and then create arrays of "just the elements you need". Example:
% create an index of all the elements that are worth computing:
worthComputing = find(k1(:)~=0);
% now create sub-arrays of all the other arrays... a little bit expensive on memory,
% but much faster for computation:
kw = k(worthComputing);
k1w = k1(worthComputing);
k2w = k2(worthComputing);
k3w = k3(worthComputing);
% now we'll compute all the results of the innermost for loop in single statements:
E_int = interp1(k_vec,E_vec,kw,'spline','extrap');
beta = c*gamma./kw.*sqrt(E_int));
k30 = k3w + beta*k1w;
k0 = sqrt(k1w.^2 + k2w.^2 + k30.^2);
Ek0 = 1.453*(k0.^4/((1 + k0.^2).^(17/6)));
% the next line has dk1, dk2, dk3 ... not sure what they are? Not shown to be initialized. Assuming scalars as they are not indexed.
B = sigmaiso*sqrt((Ek0./(k0.^2))*((dk1*dk2*dk3)/(4*pi)));
C1 = ((beta.*k1w.^2).*(k0.^2 - 2*k30.^2 + k30.*beta.*k1w))./(kw.^2.*(k1w.^2 + k2w.^2));
C2 = ((k2w.*(k0.^2))./((k1w.^2 + k2w.^2).^(3/2))).*atan2((beta.*k1w.*sqrt(k1w.^2 + ...
k2w.^2)),(k0.^2 - k30.*beta.*k1w));
xhsi1 = C1 - C2.*(k2w./k1w);
xhsi2 = C1.*(k2w./k1w) + C2;
% in the next lines I am using the trick of "collapsing" the remaining indices
% in other words, Matlab figures out that I want to access the elements in C
% that correspond to the ii, jj, kk that were picked before...
Cij(1,1,worthComputing) = B.*((k2w.*xhsi1)./(k0));
Cij(1,2,worthComputing) = B.*((k3w-k1w.*xhsi1+beta.*k1w)./(k0));
Cij(1,3,worthComputing) = B.*(-k2w./(k0));
Cij(2,1,worthComputing) = B.*((k2w.*xhsi2-k3w-beta.*k1w)./(k0));
Cij(2,2,worthComputing) = B.*((-k1w.*xhsi2)./(k0));
Cij(2,3,worthComputing) = B.*(k1w./(k0));
Cij(3,1,worthComputing) = B.*(k2w.*k0./(kw.^2));
Cij(3,2,worthComputing) = B.*(-k1w.*k0./(kw.^2));
It is entirely possible there's a typo or two in the above - but this is the basic approach to vectorization.