Improve my code for parabolic equations

I have been told my code is not 'perfect', I'm not too hot on maple and it has taken me a week to get to this stage. Any help or suggestions would be very welcome!

h:=0.1: k:=0.001: r:=k/h^2:
xl:=0: xr:=1: # left and right ends of interval in x
nxpoints:=round((xr-xl)/h):
ntsteps:=5: # total number of time steps
iprint:=1: # print output every iprint time steps
printf(cat(" x,t ","%7.3f"$(nxpoints+1),"\n"),seq(i*h,i=0..nxpoints)):
format:=cat("%7.3f"$(nxpoints+2),"\n"): # format for printing output
Boundary conditions
for j to ntsteps+1 do
u[0,j]:=0: u[nxpoints,j]:=0
end do:
Initial condition
for i from 0 to nxpoints do
u[i,0]:=sin(Pi*i*h)
end do:
solution:=[[0.,seq(u[i,0],i=0..nxpoints)]]:
printf(format,op(solution[1])):
Time steps
for j from 0 to ntsteps-1 do
for i from 1 to nxpoints-1 do
u[i,j+1]:=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]
end do;
solution:=[op(solution),[(j+1)*k,seq(u[i,j+1],i=0..nxpoints)]]:
if floor((j+1)/iprint)=(j+1)/iprint then printf(format,op(solution[j+2])) end if;
end do:
Plots
for j from 1 by iprint to ntsteps+1 do
plot||j:=plot([seq([i*h,solution[j,i+2]],i=0..nxpoints)],labels=[x,u]):
end do:
plots[display]({seq(plot||(iprint*j+1),j=0..ntsteps/iprint)});
Comparison with exact solution
plottime:=0.005:
uexact:=(x,t)->sin(Pi*x)*exp(-Pi^2*t):
pexact:=plot(uexact(x,plottime),x=0..xr,labels=[x,u],linestyle=DASH):
plots[display]({pexact,plot||(floor(plottime/k)+1)});

I think I can change the for

I think I can change the for loops with seq but I don't know how to do this for the boundary and initial conditions.

Example: I think I can replace

for i from 0 to nxpoints do
u[i,0]:=sin(Pi*i*h)
end do:

With something along the lines of

seq(u[i,0]:=sin(Pi*i*h), i=0..nxpoints)
end do;

Although when I do this I get errors further up the code.

Doug Meade's picture

some ideas to get you started

In your last post, it is not correct to use := inside the seq. This should be:

seq( assign( u[i,0] = sin(Pi*i*h) ), i=0..nxpoints );

If you declare U to be an Array with appropriate dimensions at the top, then you could also do something like the following to impose the initial condition at time t=0 and the boundary conditions on both ends:

U := Array(0..nxpoints,0..ntsteps):
U[1..nxpoints,0]       := Array( 1..nxpoints, i->sin(Pi*i*h) );
U[0,       1..ntsteps] := Array( 1..ntsteps, 0 );
U[nxpoints,1..ntsteps] := Array( 1..ntsteps, 0 );

Inside your time loop you use

solution:=[op(solution),[(j+1)*k,seq(u[i,j+1],i=0..nxpoints)]]:

This is pretty inefficient. Since you know in advance the number of time steps, it's better to declare solution with its final size and to assign values one row during each time step:

Solution := Array( 0..ntsteps, 0..nxpoints ):
Solution[0,0..nxpoints] := Array( 0..nxpoints, i->u[i,0] );
for j from 0 to ntsteps-1 do
 ...
 Solution[ j+1, 0..nxpoints ] := Array( 0..nxpoints, i->u[i,j+1] );
 ...
end do

I don't have time to do more now. I hope this is correct enough to get you started (not all of the above code was tested).

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/

Thank you for your reply. I

Thank you for your reply. I have replaced

Initial condition
for i from 0 to nxpoints do
u[i,0]:=sin(Pi*i*h)
end do:
solution:=[[0.,seq(u[i,0],i=0..nxpoints)]]:
printf(format,op(solution[1])):

with

Initial condition
seq(assign( u[i,0]=sin(Pi*i*h) ),i=0..nxpoints);
end do:
solution:=[[0.,seq(u[i,0],i=0..nxpoints)]]:
printf(format,op(solution[1])):

After the first plot command it gives me and error and pulls me back to the seq. I can't seen a reason for the error, the code up until the error is below. Any help again is greatly appreciated.

restart;
h:=0.1: k:=0.001: r:=k/h^2:
xl:=0: xr:=1: # left and right ends of interval in x
nxpoints:=round((xr-xl)/h):
ntsteps:=5: # total number of time steps
iprint:=1: # print output every iprint time steps
printf(cat(" x,t ","%7.3f"$(nxpoints+1),"\n"),seq(i*h,i=0..nxpoints)):
format:=cat("%7.3f"$(nxpoints+2),"\n"): # format for printing output
Boundary conditions
for j to ntsteps+1 do
u[0,j]:=0: u[nxpoints,j]:=0
end do:
Initial condition
seq(assign(u[i,0]=sin(Pi*i*h)),i=0..nxpoints);
end do:
solution:=[[0.,seq(u[i,0],i=0..nxpoints)]]:
printf(format,op(solution[1])):
Time steps
for j from 0 to ntsteps-1 do
for i from 1 to nxpoints-1 do
u[i,j+1]:=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]
end do;
solution:=[op(solution),[(j+1)*k,seq(u[i,j+1],i=0..nxpoints)]]:
if floor((j+1)/iprint)=(j+1)/iprint then printf(format,op(solution[j+2])) end if;
end do:
Plots
for j from 1 by iprint to ntsteps+1 do
plot||j:=plot([seq([i*h,solution[j,i+2]],i=0..nxpoints)],labels=[x,u]):
end do:
plots[display]({seq(plot||(iprint*j+1),j=0..ntsteps/iprint)});
x,t 0.000 0.100 0.200 0.300 0.400 0.500 0.600 0.700 0.800 0.900 1.000
Error, reserved word `end` unexpected

Oops, cut that a bit

Oops, cut that a bit short.

Also, with regards to the arrays, we have been banned from using the maple array. Not sure of the reasoning behind it.

Thanks again.

Doug Meade's picture

Homework?

These comments make it seem that this is part of a homework assignment. If so, is it within your course/school rules to be getting help on this forum?

Regardless, your instructor should be able to provide some local assistance.

The rule about not using arrays is odd. You give someone a tool, then tell them they can't use all of it. Who has an electric screwdriver but always uses it as if it were a standard screwdriver?

Anyway, back to your code. The only problem I see in your code is an extra "end do" after the seq in the initial condition. With that commented out, I get the solution at 0.001, 0.002, 0.003, 0.004, and 0.005 and the plot shows 6 curves.

If you are not going to do anything with the other timesteps, there is no reason to save them in solution. You can also replace the conditional based on floor(X/N)=X/N with X mod N = 0. If you do this, then the loop to create the plots will change to "for j from 1 by iprint to ntsteps+1 do" to "for j from 1 to nops(solution) do". In fact, there is no reason to make the separate plots. The entire plot can be created in one line with nested seq's - just be careful to adjust the indices on solution.

Another approach would be to not save all of the results (solution) and to simply create the plot every iprint timesteps.

Not knowing your rules, I am not going to post the code I have. It's not very different from what you posted originally.

I hope this is helpful,

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/

Its all about experience.

Thanks Doug. This is not an official coursework assignment. I am not even taking the modul from which this example comes from. I am trying to gain some experience in maple before next year when I have some modules that will require programming skills. Again the condition on arrays seemed odd to me but maybe it will get me more involved in the programming. I will try your tips and let you know how I do.

Thankyou.

Doug Meade's picture

fair enough

Thanks for the explanation.

Now we can hit you full force with our ideas.

Take some time to think about the suggestions in my previous post. Show us where you get, and what more you'd like to do.

Are there any other restrictions on the uses of Maple? Can LinearAlgebra be used?

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/
acer's picture

ban on array, or Array?

I wonder whether there was a "ban" on using array(), rather than the newer Array().

acer

I asked that this morning

I asked that this morning and its a ban on both, this ban also includes matrices and other built in functions.

Doug Meade's picture

be careful with the language

To me, a "matrix" is a rectangular grid of numbers (or other objects). You use a "matrix" when you refer to u[i,j] (or even just v[i] - a "vector" is also a "matrix").

Not using other "built-in" functions?

I think I understand what you are being told, but the language needs to be watched carefully.

I believe the comment about matrices is really a restriction from using linear algebra or matrix operations. The comment about built-in functions is probably a restriction from using high-level commands such as dsolve.

On one hand I admit that I am being a little picky. But, I do believe it is important to watch the way instructions are given.

While I understand some of this, I do stand by my earlier comments that it is a little counterproductive to not use the full power of the software. It sounds as though you are being forced to use Maple as if it were a standard 20th century programming language.

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/

Update

This is my code in its current state.

restart;
h:=0.1: k:=0.001: r:=k/h^2:
xl:=0: xr:=1: # left and right ends of interval in x
nxpoints:=round((1/2)*(xr-xl)/h):
ntsteps:=5: # total number of time steps
iprint:=1: # print output every iprint time steps
printf(cat(" x,t ","%7.3f"$(nxpoints+1),"\n"),seq(i*h,i=0..nxpoints)):
format:=cat("%7.3f"$(nxpoints+2),"\n"): # format for printing output
Boundary conditions
for j to ntsteps+1 do
u[0,j]:=0: u[nxpoints,j]:=0
end do:
Initial condition
seq(assign(u[i,0]=sin(i*h)),i=0..nxpoints);
solution:=[[0.,seq(u[i,0],i=0..nxpoints)]]:
printf(format,op(solution[1])):
Time steps
for j from 0 to ntsteps-1 do
for i from 1 to nxpoints-1 do
u[i,j+1]:=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]
end do;
i=nxpoints: u[i,j+1]:=2*r*u[i-1,j]+(1-2*r)*u[i,j]; # at the point x=0.500, taking account of symmetry
for i from nxpoints to 1 do
u[i,j]=u[1-i,j]
end do:
solution:=[op(solution),[(j+1)*k,seq(u[i,j+1],i=0..nxpoints)]]:
if (j+1) mod iprint = 0 then printf(format,op(solution[j+2])) end if;
end do:
Plots
for j from 1 to nops(solution) do
plot||j:=plot([seq([i*h,solution[j,i+2]],i=0..nxpoints)],labels=[x,u]):
end do:
plots[display]({seq(plot||(iprint*j+1),j=0..ntsteps/iprint)});
x,t 0.000 0.100 0.200 0.300 0.400 0.500
0.000 0.000 0.100 0.199 0.296 0.389 0.479
0.001 0.000 0.100 0.198 0.295 0.389 0.461
0.002 0.000 0.100 0.198 0.295 0.387 0.447
0.003 0.000 0.100 0.198 0.294 0.384 0.435
0.004 0.000 0.099 0.198 0.294 0.380 0.425
0.005 0.000 0.099 0.198 0.293 0.376 0.416

Comparison with exact solution
plottime:=0.005:
uexact:=(x,t)->4*cos(1/2)*sum(((-1)^n)/((2*n+1)^(2)*Pi^(2)-1)*exp(-(2*n+1)^(2)*Pi^(2)*t)*sin((2*n+1)*Pi*x),n=0..100):
pexact:=plot(uexact(x,plottime),x=0..xr,labels=[x,u],linestyle=DASH):
plots[display]({pexact,plot||(floor(plottime/k)+1)});

I have changed my definition of nxpoints at the top in a crude attempt to take advantage of the symmetry of the problem. This has cut down on the computations needed but I have not been able to plot the whole graph so this symettry isn't being carried through. I have tried to enter the extra values needed using this code:

for i from nxpoints to 1 do
u[i,j]=u[1-i,j]
end do:

It seems rather ineffective, it doesn't change any of the output or graphs and also doesn't result in any errors. Plotting the whole graph is the last piece of the puzzle, any changes to code after getting this sorted would be more for efficency then actually getting the answer.

Doug, I used your suggestion for X mod N = 0 and it has worked nicely. I tried to use nested seq's but failed miserably.

Finally, I tried to replace

for j from 0 to ntsteps-1 do
for i from 1 to nxpoints-1 do
u[i,j+1]:=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]
end do;

with

seq(assign(u[i,j+1]=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]),j=0..nxsteps-1,i=1..nxpoints-1);

it didn't work and threw up many errors.

Doug Meade's picture

nested seq

I don't have time right now to look at your full code, but I can comment on the nested seq. First, this is pretty unnatural. I would keep the nested do loops.

You should be able to replace

for j from 0 to ntsteps-1 do
for i from 1 to nxpoints-1 do
u[i,j+1]:=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]
end do;
end do;    # not in your code

with

seq(
 seq( # missing from your code
  assign(u[i,j+1]=r*u[i-1,j]+(1-2*r)*u[i,j]+r*u[i+1,j]),
  j=0..nxsteps-1
 ),         # this closing parenthesis was missing as well
 i=1..nxpoints-1
);

I encourage the use of whitespace to make code more readable. Splitting commands between lines, and indenting, work also. (To see the spacing in MaplePrimes, enclose the code with "pre" tags - for preformat - which are very difficult to show in a post.)

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/

I have put some code in to

I have put some code in to try and give results for x between 0.6 and 1 (the 6th to 10th steps), I have added

for i from nxpoints+1 to 2*nxpoints do
u[i,j]=u[1-i,j]
end do;

Into my timestep loop immediately before

i=nxpoints: u[i,j+1]:=2*r*u[i-1,j]+(1-2*r)*u[i,j];

The problem is my results are only printing up to x=0.5 leaving half the solution out. This problem follows into my graphs and I only get a comparison up to x=0.5. I think I need to extend the output up to the correct number of points but I'm finding this difficult due to my definition of nxpoints at the top of the code.

Any ideas?

Doug Meade's picture

two suggestions

You said you added this code:

for i from nxpoints+1 to 2*nxpoints do
  u[i,j]=u[1-i,j]
end do;

First, you need ":=", not "=", to make an assignment.

Second, I doubt you mean u[1-i,j]. You are probably hoping to implement u(x,t)=u(1-x,t), for x=1/2..1, but this will be coded as u[i,j] := u[2*nxpoints+1-i,j], for i=nxpoints+1..2*nxpoints.

To be honest, I think I would prefer to implement this symmetry as u[nxpoints+i,j] := u[nxpoints-i,j].

Try this and see if it doesn't fix your plotting problems as well.

Doug

---------------------------------------------------------------------
Douglas B. Meade
Math, USC, Columbia, SC 29208  E-mail: mailto:meade@math.sc.edu       
Phone:  (803) 777-6183         URL:    http://www.math.sc.edu/~meade/

Thanks for all your help.

Doug, thanks for your help. I have finally got a solution that works.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
}