I wrote a function to solve the 1D wave equation with FDM. Therefore i used second order accuracy in time and fourth order in space and an explicit FD scheme.
I already implemented the solver function in Matlab with an matrix-vector-multiplication approach (alternative this can be done iterative) with periodic boundary conditions.
To verify the code i used the Method of Manufactured Solution. My approach is to assume the solution as
p(t,x)=sin(x+t)+sin(x-t)
which is periodic and sufficient smooth and differentiable. I implemented a source term f which is as well as the initial data input for the following function
function [x,t,P_End]= MMS(f,I,G,L,v,T,J,CFL,x)
% Initialisation
deltax=x(2)-x(1);
deltat=CFL*deltax/abs(v);
c=(v*deltat/deltax)^2;
t=(0:deltat:T);
N=length(t);
A=zeros(J,J);
for k=1:J
% periodic boundary condition
if k==1
A(1,1)=-c*5/2;
A(1,2)=c*4/3;
A(1,3)=c/12;
A(1,J-1)=c/12;
A(1,J)=c*4/3;
elseif k==J
A(J,1)=c*4/3;
A(J,2)=c/12;
A(J,J-2)=c/12;
A(J,J-1)=c*4/3;
A(J,J)=-c*5/2;
elseif k==2
A(2,J)=c/12;
A(2,1)=c*4/3;
A(2,2)=-c*5/2;
A(2,3)=c*4/3;
A(2,4)=c/12;
elseif k==J-1
A(J-1,1)=c*1/12;
A(J-1,J-1)=-c*5/2;
A(J-1,J)=c*4/3;
A(J-1,J-2)=c*4/3;
A(J-1,J-3)=c*1/12;
else
A(k,k-2)=c/12;
A(k,k-1)=c*4/3;
A(k,k)=-c*5/2;
A(k,k+1)=c*4/3;
A(k,k+2)=c/12;
end
end
%Allocate memory
P_0=zeros(J,1);
b=zeros(J,1);
H=zeros(J,1);
%Initial data read in
for i=1:J
P_0(i)=I(x(i));
b(i)=f(x(i),t(1));
H(i)=G(x(i));
end
%Calculation of first time step separate because to time steps back
%are needed in the iteration
P_1=0.5*A*P_0+(deltat^2/2)*b+2*deltat*H+P_0;
P_n_minus_1=P_0;
P_n=P_1;
P_End=zeros(N,J); % Solution matrix
P_End(1,:)=P_0;
P_End(2,:)=P_1;
for n=2:N
for i=1:J
b(i)=f(x(i),t(n));
end
%Iterative calculation for t_2,...,t_N
P_n_plus_1=A*P_n+(deltat^2)*b-P_n_minus_1+2*P_n;
%Overwriting
P_n_minus_1=P_n;
P_n=P_n_plus_1;
P_End(n,:)=P_n_plus_1;
end
end
The function call is then
clear all; clc; close all;
%% Initialisierung
% Grid points in space x_0,...x_L
x = -2 : 0.01 : 2;
J = length(x);
xDelta = x(2) - x(1);
T = 2;
v = 0.5; %velocity constant
CFL = 0.5; %Courant Friedrich Lewis number
%Source term right-hand side of the wave equation
f = #(x,t) abs(v^2-1)*(sin(x+t)+sin(x-t));
%Initial data for the estimated sound pressure function p(t,x), t=0
I = #(x) 2*sin(x);
% \partial p/ \partial t , t=0
G = #(x) 0;
[x,t,P_End]= MMS(f,I,G,v,T,J,CFL,x);
This initial data and source term input leads to a solution that proceed like the assumed solution but in range ob `+/- 10^24.
What an i doing wrong here? I already reviewed the code hundred of times but could not detect any code mistakes.
Thanks for any hints!
I am currently working on a molecular dynamics simulation of polymers in solution, this is one of the subroutines which calculates the potential energy of the system and the force exerted on each monomer.
function eval_force()
% eval_force.m IS USED FOR EVALUATING FORCE
% THE STRATEGY USUALLY ADOPTED FOR A LENNARD-JONES OR AS A MATTER OF FACT
% ANY PAIR-WISE INTERACTING SYSTEM IS AS FOLLOWS:
% 1. EVALUATE THE DISTANCE BETWEEN TWO PAIRS OF ATOMS
% 2. ENSURE THAT MINIMUM IMAGE CONVENTION (MIC) IS FOLLOWED
% 3. IF THE DISTANCE OBTAINED THROUGH MIC IS GREATER THAN THE CUT OFF
% DISTANCE MOVE TO NEXT PAIR
% 4. ELSE EVALUATE POTENTIAL ENERGY AND CALCULATE FORCE COMPONENTS
% 5. F(i,j) = -F(j,i)
global MASS KB TEMPERATURE NUM_ATOMS LENGTH TSTEP;
global EPS SIG R_CUT GAMMA POT_E;
global POSITION VELOCITY FORCE STO;
dr = zeros(3,1);
drh = zeros(3,1);
FORCE(:) = 0.0;
POT_E = 0.0;
for ( i=1:NUM_ATOMS )
for ( j=i+1:NUM_ATOMS )
dist2 = 0.0; % VARIABLE dist2 STORES DISTANCE BETWEEN PAIR (i,j)
% FIRST FIND OUT THE DIFFERENCE IN X,Y AND Z COORDINATES
% VARIABLE dr IS USED FOR THIS PURPOSE
for(k = 1:3)
dr(k) = POSITION(i,k) - POSITION(j,k);
% THESE STEPS ENSURE MINIMUM IMAGE CONVENTION IS FOLLOWED
if(dr(k) > LENGTH/2.0)
dr(k) = dr(k) - LENGTH;
end
if(dr(k) < -LENGTH/2.0)
dr(k) = dr(k) + LENGTH;
end
% MINIMUM IMAGE CONVENTION ENDS HERE
dist2 = dist2 + dr(k)*dr(k); % dist2 IS BASED UPON MIC
end
if(dist2 <= R_CUT*R_CUT) % IF THE CUT OFF CRITERIA IS SATISFIED
dist2i = power(SIG,2)/dist2;
dist6i = power(dist2i,3);
dist12i = power(dist6i,2);
POT_E = POT_E + EPS * (dist12i - 2*dist6i) + 33.34 * EPS * power(sqrt(dist2) - SIG,2)/(2 * power(SIG,2)); % STORES THE POTENTIAL ENERGY
Ff = 12.0 * EPS * (dist12i-dist6i) - 33.34 * EPS * (sqrt(dist2) - SIG)/(dist2i * sqrt(dist2) * power(SIG,2));
Ff = Ff * dist2i;
for(k = 1:3)
FORCE(i,k) = FORCE(i,k) + Ff*dr(k)- GAMMA*VELOCITY(i,k);
FORCE(j,k) = FORCE(j,k) - Ff*dr(k)- GAMMA*VELOCITY(j,k);
end
end
end
end
end
How can I make a loop for the "33.34 * EPS * power(sqrt(dist2) - SIG,2)/(2 * power(SIG,2))" part under POT_E which is the harmonic potential, so it only evaluates the distance between atoms for the nearest ones (for j=i+1 to 4).
After having a quick look at your code, I'd suggest the following ideas:
Calculate all-to-all distances at once using pdist and store it in a matrix, say AllDist.
The conditions based on LENGTH can be applied directly on AllDist.
Since you need to find four nearest neighbors, you need to have a single loop iterating through the rows (or columns) of AllDist, which sorts the current row (or column) and gives you four nearest neighbors. Note that for each atom, you'd get 0 as the nearest distance as this is the "self-distance". Ignore this.
If you have access to Matlab's Parallel Computing Toolbox, try to use it (parfor) where appropriate to accelerate your simulation.
I am trying to solve a system of differential equations by writing code in Matlab. I am posting on this forum, hoping that someone might be able to help me in some way.
I have a system of 10 coupled differential equations. It is a vector-host epidemic model, which captures the transmission of a disease between human population and insect population. Since it is a simple system of differential equations, I am using solvers (ode45) for non-stiff problem type.
There are 10 differential equations, each representing 10 different state variables. There are two functions which have the same system of 10 coupled ODEs. One is called NoEffects_derivative_6_15_2012.m which contains the original system of ODEs. The other function is called OnlyLethal_derivative_6_15_2012.m which contains the same system of ODEs with an increased withdrawal rate starting at time, gamma=32 %days and that withdrawal rate decays exponentially with time.
I use ode45 to solve both the systems, using the same initial conditions. Time vector is also the same for both systems, going from t0 to tfinal. The vector tspan contains the time values going from t0 to tfinal, each with a increment of 0.25 days, making a total of 157 time values.
The solution values are stored in matrices ye0 and yeL. Both these matrices contain 157 rows and 10 columns (for the 10 state variable values). When I compare the value of the 10th state variable, for the time=tfinal, in the matrix ye0 and yeL by plotting the difference, I find it to be becoming negative for some time values. (using the command: plot(te0,ye0(:,10)-yeL(:,10))). This is not expected. For all time values from t0 till tfinal, the value of the 10 state variable, should be greater, as it is the solution obtained from a system of ODEs which did not have an increased withdrawal rate applied to it.
I am told that there is a bug in my matlab code. I am not sure how to find out that bug. Or maybe the solver in matlab I am using (ode45) is not efficient and does give this kind of problem. Can anyone help.
I have tried ode23 and ode113 as well, and yet get the same problem. The figure (2), shows a curve which becomes negative for time values 32 and 34 and this is showing a result which is not expected. This curve should have a positive value throughout, for all time values. Is there any other forum anyone can suggest ?
Here is the main script file:
clear memory; clear all;
global Nc capitalambda muh lambdah del1 del2 p eta alpha1 alpha2 muv lambdav global dims Q t0 tfinal gamma Ct0 b1 b2 Ct0r b3 H C m_tilda betaHV bitesPERlanding IC global tspan Hs Cs betaVH k landingARRAY muARRAY
Nhh=33898857; Nvv=2*Nhh; Nc=21571585; g=354; % number of public health centers in Bihar state %Fix human parameters capitalambda= 1547.02; muh=0.000046142; lambdah= 0.07; del1=0.001331871263014; del2=0.000288658; p=0.24; eta=0.0083; alpha1=0.044; alpha2=0.0217; %Fix vector parameters muv=0.071428; % UNIT:2.13 SANDFLIES DEAD/SAND FLY/MONTH, SOURCE: MUBAYI ET AL., 2010 lambdav=0.05; % UNIT:1.5 TRANSMISSIONS/MONTH, SOURCE: MUBAYI ET AL., 2010
Ct0=0.054;b1=0.0260;b2=0.0610; Ct0r=0.63;b3=0.0130;
dimsH=6; % AS THERE ARE FIVE HUMAN COMPARTMENTS dimsV=3; % AS THERE ARE TWO VECTOR COMPARTMENTS dims=dimsH+dimsV; % THE TOTAL NUMBER OF COMPARTMENTS OR DIFFERENTIAL EQUATIONS
gamma=32; % spraying is done of 1st feb of the year
Q=0.2554; H=7933615; C=5392890;
m_tilda=100000; % assumed value 6.5, later I will have to get it for sand flies or mosquitoes betaHV=66.67/1000000; % estimated value from the short technical report sent by Anuj bitesPERlanding=lambdah/(m_tilda*betaHV); betaVH=lambdav/bitesPERlanding; IC=zeros(dims+1,1); % CREATES A MATRIX WITH DIMS+1 ROWS AND 1 COLUMN WITH ALL ELEMENTS AS ZEROES
t0=1; tfinal=40; for j=t0:1:(tfinal*4-4) tspan(1)= t0; tspan(j+1)= tspan(j)+0.25; end clear j;
% INITIAL CONDITION OF HUMAN COMPARTMENTS q1=0.8; q2=0.02; q3=0.0005; q4=0.0015; IC(1,1) = q1*Nhh; IC(2,1) = q2*Nhh; IC(3,1) = q3*Nhh; IC(4,1) = q4*Nhh; IC(5,1) = (1-q1-q2-q3-q4)*Nhh; IC(6,1) = Nhh; % INTIAL CONDITIONS OF THE VECTOR COMPARTMENTS IC(7,1) = 0.95*Nvv; %80 PERCENT OF TOTAL ARE ASSUMED AS SUSCEPTIBLE VECTORS IC(8,1) = 0.05*Nvv; %20 PRECENT OF TOTAL ARE ASSUMED AS INFECTED VECTORS IC(9,1) = Nvv; IC(10,1)=0;
Hs=2000000; Cs=3000000; k=1; landingARRAY=zeros(tfinal*50,2); muARRAY=zeros(tfinal*50,2);
[te0 ye0]=ode45(#NoEffects_derivative_6_15_2012,tspan,IC); [teL yeL]=ode45(#OnlyLethal_derivative_6_15_2012,tspan,IC);
figure(1) subplot(4,3,1); plot(te0,ye0(:,1),'b-',teL,yeL(:,1),'r-'); xlabel('time'); ylabel('S'); legend('susceptible humans'); subplot(4,3,2); plot(te0,ye0(:,2),'b-',teL,yeL(:,2),'r-'); xlabel('time'); ylabel('I'); legend('Infectious Cases'); subplot(4,3,3); plot(te0,ye0(:,3),'b-',teL,yeL(:,3),'r-'); xlabel('time'); ylabel('G'); legend('Cases in Govt. Clinics'); subplot(4,3,4); plot(te0,ye0(:,4),'b-',teL,yeL(:,4),'r-'); xlabel('time'); ylabel('T'); legend('Cases in Private Clinics'); subplot(4,3,5); plot(te0,ye0(:,5),'b-',teL,yeL(:,5),'r-'); xlabel('time'); ylabel('R'); legend('Recovered Cases');
subplot(4,3,6);plot(te0,ye0(:,6),'b-',teL,yeL(:,6),'r-'); hold on; plot(teL,capitalambda/muh); xlabel('time'); ylabel('Nh'); legend('Nh versus time');hold off;
subplot(4,3,7); plot(te0,ye0(:,7),'b-',teL,yeL(:,7),'r-'); xlabel('time'); ylabel('X'); legend('Susceptible Vectors');
subplot(4,3,8); plot(te0,ye0(:,8),'b-',teL,yeL(:,8),'r-'); xlabel('time'); ylabel('Z'); legend('Infected Vectors');
subplot(4,3,9); plot(te0,ye0(:,9),'b-',teL,yeL(:,9),'r-'); xlabel('time'); ylabel('Nv'); legend('Nv versus time');
subplot(4,3,10);plot(te0,ye0(:,10),'b-',teL,yeL(:,10),'r-'); xlabel('time'); ylabel('FS'); legend('Total number of human infections');
figure(2) plot(te0,ye0(:,10)-yeL(:,10)); xlabel('time'); ylabel('FS(without intervention)-FS(with lethal effect)'); legend('Diff. bet. VL cases with and w/o intervention:ode45');
The function file: NoEffects_derivative_6_15_2012
function dx = NoEffects_derivative_6_15_2012( t , x )
global Nc capitalambda muh del1 del2 p eta alpha1 alpha2 muv global dims m_tilda betaHV bitesPERlanding betaVH
dx = zeros(dims+1,1); % t % dx
dx(1,1) = capitalambda-(m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/(x(7,1)+x(8,1))-muh*x(1,1);
dx(2,1) = (m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/(x(7,1)+x(8,1))-(del1+eta+muh)*x(2,1);
dx(3,1) = p*eta*x(2,1)-(del2+alpha1+muh)*x(3,1);
dx(4,1) = (1-p)*eta*x(2,1)-(del2+alpha2+muh)*x(4,1);
dx(5,1) = alpha1*x(3,1)+alpha2*x(4,1)-muh*x(5,1);
dx(6,1) = capitalambda -del1*x(2,1)-del2*x(3,1)-del2*x(4,1)-muh*x(6,1);
dx(7,1) = muv*(x(7,1)+x(8,1))-bitesPERlanding*betaVH*x(7,1)*x(2,1)/(x(6,1)+Nc)-muv*x(7,1);
%dx(8,1) = lambdav*x(7,1)*x(2,1)/(x(6,1)+Nc)-muvIOFt(t)*x(8,1);
dx(8,1) = bitesPERlanding*betaVH*x(7,1)*x(2,1)/(x(6,1)+Nc)-muv*x(8,1);
dx(9,1) = (muv-muv)*x(9,1);
dx(10,1) = (m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/x(9,1);
The function file: OnlyLethal_derivative_6_15_2012
function dx=OnlyLethal_derivative_6_15_2012(t,x)
global Nc capitalambda muh del1 del2 p eta alpha1 alpha2 muv global dims m_tilda betaHV bitesPERlanding betaVH k muARRAY
dx=zeros(dims+1,1);
% the below code saves some values into the second column of the two arrays % t muARRAY(k,1)=t; muARRAY(k,2)=artificialdeathrate1(t); k=k+1;
dx(1,1)= capitalambda-(m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/(x(7,1)+x(8,1))-muh*x(1,1);
dx(2,1)= (m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/(x(7,1)+x(8,1))-(del1+eta+muh)*x(2,1);
dx(3,1)=p*eta*x(2,1)-(del2+alpha1+muh)*x(3,1);
dx(4,1)=(1-p)*eta*x(2,1)-(del2+alpha2+muh)*x(4,1);
dx(5,1)=alpha1*x(3,1)+alpha2*x(4,1)-muh*x(5,1);
dx(6,1)=capitalambda -del1*x(2,1)-del2*( x(3,1)+x(4,1) ) - muh*x(6,1);
dx(7,1)=muv*( x(7,1)+x(8,1) )- bitesPERlanding*betaVH*x(7,1)*x(2,1)/(x(6,1)+Nc) - (artificialdeathrate1(t) + muv)*x(7,1);
dx(8,1)= bitesPERlanding*betaVH*x(7,1)*x(2,1)/(x(6,1)+Nc)-(artificialdeathrate1(t) + muv)*x(8,1);
dx(9,1)= -artificialdeathrate1(t) * x(9,1);
dx(10,1)= (m_tilda)*bitesPERlanding*betaHV*x(1,1)*x(8,1)/x(9,1);
The function file: artificialdeathrate1
function art1=artificialdeathrate1(t)
global Q Hs H Cs C
art1= Q*Hs*iOFt(t)/H + (1-Q)*Cs*oOFt(t)/C ;
The function file: iOFt
function i = iOFt(t)
global gamma tfinal Ct0 b1
if t>=gamma && t<=tfinal
i = Ct0*exp(-b1*(t-gamma));
else
i =0;
end
The function file: oOFt
function o = oOFt(t)
global gamma Ct0 b2 tfinal
if (t>=gamma && t<=tfinal)
o = Ct0*exp(-b2*(t-gamma));
else
o = 0;
end
If your working code is even remotely as messy as the code you posted, then that should IMHO the first thing you should address.
I cleaned up iOFt, oOFt a bit for you, since those were quite easy to handle. I tried my best at NoEffects_derivative_6_15_2012. What I'd personally change to your code is using decent indexes. You have 10 variables, there is no way that if you let your code rest for a few weeks or months, that you will remember what state 7 is for example. So instead of using (7,1), you might want to rewrite your ODE either using verbose names and then retrieving/storing them in the x and dx vectors. Or use indexes that make it clear what is happening.
E.g.
function ODE(t,x)
insectsInfected = x(1);
humansInfected = x(2);
%etc
dInsectsInfected = %some function of the rest
dHumansInfected = %some function of the rest
% etc
dx = [dInsectsInfected; dHumansInfected; ...];
or
function ODE(t,x)
iInsectsInfected = 1;
iHumansInfected = 2;
%etc
dx(iInsectsInfected) = %some function of x(i...)
dx(iHumansInfected) = %some function of x(i...)
%etc
When you don't do such things, you might end up using x(6,1) instead of e.g. x(3,1) in some formulas and it might take you hours to spot such a thing. If you use verbose names, it takes a bit longer to type, but it makes debugging a lot easier and if you understand your equations, it should be more obvious when such an error happens.
Also, don't hesitate to put spaces inside your formulas, it makes reading much easier. If you have some sub-expressions that are meaningful (e.g. if (1-p)*eta*x(2,1) is the number of insects that are dying of the disease, just put it in a variable dyingInsects and use that everywhere it occurs). If you align your assignments (as I've done above), this might add to code that is easier to read and understand.
With regard to the ODE solver, if you are sure your implementation is correct, I'd also try a solver for stiff problems (unless you are absolutely sure you don't have a stiff system).