(Note: The MATLAB coding described in this appendix has been tested on a Windows 7 computer. The equivalent system calls should work on a Unix or Mac computer, but have not been tested.)
Sometimes it is desirable to perform some calculations in a language other than MATLAB. Possible reasons for this are that (1) a complicated, working, calculation program already exists; or (2) it is difficult or even impossible to vectorize a MATLAB program but desirable to utilize the calculation speed of some fully compiled optimized code in a language such as C or FORTRAN.
MATLAB has built-in capabilities for doing this.1,2 The MATLAB capabilities are significant and merit investigation if this type of interface is desired. There are limitations, however, as to what compilers and languages are supported. The technique described in this appendix is a “quick and dirty” patch that works well provided you can write or modify and compile code with a compiler and language of your choice into an executable program.
The procedure is very straightforward and utilizes MATLAB's capability of executing a system command and then waiting for its completion:
Following is the MATLAB script run_ppt4.m
, with a calling program for different versions of ppt4.m
:
% run_ppt4.m a convenience script for running and plotting ppt4 results
% with a Fortran interface
rad = 0.25; step = .1;
y1 = 15 + rad + step; y2 = 40;
y = [y1];
while y(end) < y2
y = [y, y(end) + step];
step = 1.25*step;
end
y = y(1 : end-1)
tic
% Comment out the undesired choice below
% This section calls the fortran program --------------
x = 0
xy_fortran = [x, y]'
save ppt4_data.dat xy_fortran -ascii
dos 'ppt4_fortran.exe'
fid = fopen('ppt4_ftn_out.dat','rt'), % open the file
volts = (fscanf(fid, '%g'))'; % read the file
% This section runs the program in Matlab ----------------
% volts = ppt4(x, y)
% ---------------------------------------------
toc
y = [15 + rad, y, 40]; volts = [1.0, volts, 0];
coefs = polyfit(y, volts, 3)
curve = polyval(coefs,y);
figure(1);
plot(y, volts, 'xk', y, curve, 'k')
figure(2);
E_curve = -(3*coefs(1)*y.^2 + 2*coefs(2)*y + coefs(3));
plot (y, E_curve, 'k')
MATLAB script run_ppt4.m
is an example of this procedure, using the probabilistic potential theory program ppt4.m
, from Chapter 11, as an example. The run_ppt4.m
program is written to call either the MATLAB or FORTRAN version of the program (simply comment out the undesired choice).
The FORTRAN source code ppt4_ftn.f90
, the FORTRAN version of ppt4.m
, is as follows:
! fortran version of ppt4.m
implicit integer (t)
implicit real*8 (a-h, o-s, u-z)
real*8 y_pt(1000) ! y scan data points
real*8 walls(100,5) ! wall data
real*8, allocatable :: volts(:), dists(:,:), results(:)
real*8 stuff(3) ! return from boundary checkers: 1 = distance, 2,3 = closest point
integer hit_boundary
pi = 4*atan(1.0)
call srand(12345)
! get the data
call gather_data(x_pt, nr_pts, y_pt, nr_walls, walls)
allocate (volts(nr_pts), dists(nr_walls,4), results(nr_pts))
print *, 'nr_pts = ', nr_pts
print *, 'x_pt = ', x_pt
do i = 1, nr_pts
print *, i, y_pt(i)
end do
do i = 1, nr_walls
print '(5f10.3)', (walls(i,j), j = 1,5)
end do
tic = time8()
do i_nr = 1, nr_pts ! starting point counter
nr_iters = 50000
nr_ones = 0
do iter = 1, nr_iters ! iteration counter
hit_boundary = 0
x = x_start
y = y_pt(i_nr)
do while (hit_boundary < = 0) ! wandering point loop
do i_wall = 1, nr_walls ! examine all the boundary conditions
if (walls(i_wall,1) .eq. 1) then
call hor_line(i_wall, walls, x, y, stuff)
else if (walls(i_wall,1) .eq. 2) then
call vert_line(i_wall, walls, x, y, stuff)
else
call circle_dist(i_wall, walls, x, y, stuff)
end if
do j = 1, 3
dists(i_wall,j) = stuff(j)
end do
dists(i_wall,4) = walls(i_wall,5) ! keep the voltage with us
end do
d = 1.e20
index = 0
do i = 1, nr_walls
if (dists(i,1) < d) then
d = dists(i,1)
index = i
end if
end do
rad_step = dists(index,1)
p1x = dists(index,2)
p1y = dists(index,3)
v = dists(index,4)
phi = atan2(p1y-y , p1x-x)
p2x = x + rad_step*cos(phi + pi/2)
p2y = y + rad_step*sin(phi + pi/2)
p3x = x + rad_step*cos(phi + pi)
p3y = y + rad_step*sin(phi + pi)
p4x = x + rad_step*cos(phi + 3*pi/2)
p4y = y + rad_step*sin(phi + 3*pi/2)
volts = dists(index,4);
prob = rand(0)
if (prob < 1./4.) then
x = p1x
y = p1y
else if (prob < 1./2.) then
x = p2x
y = p2y
else if (prob < 3./4.) then
x = p3x
y = p3y
else
x = p4x
y = p4y
end if
! print *, prob, x, y
! if prob < 1/4 we hve an extraction
if (prob < 1./4.) then
if (v .eq. 0) then ! check for voltage
hit_boundary = 1
else
hit_boundary = 2
end if
end if
end do
if (hit_boundary .eq. 2) nr_ones = nr_ones + 1
! print *, 'hit_boundary = ', hit_boundary
! pause
end do
v_at_point = (1.*nr_ones)/nr_iters
print *, 'y, v = ', y_pt(i_nr), v_at_point
results(i_nr) = v_at_point
end do
toc = time8() - tic
print *, 'execution time = ', toc
open (3, file = 'ppt4_ftn_out.dat')
do i = 1, nr_pts
print '(2f12.5)', y_pt(i), results(i)
write (3,'(f12.5)') results(i)
end do
close (3)
stop
end
! ---------------------------------------------
subroutine circle_dist(i_wall, walls, pt_x, pt_y, stuff)
implicit real*8 (a-h, o-z)
real*8 walls(100,5), stuff(3)
rad = walls(i_wall,2)
x0 = walls(i_wall,3)
y0 = walls(i_wall,4)
stuff(1) = sqrt((pt_x - x0)**2 + (pt_y - y0)**2) - rad
theta = atan2(pt_y - y0, pt_x - x0)
stuff(2) = x0 + rad*cos(theta)
stuff(3) = y0 + rad*sin(theta)
return
end
! ---------------------------------------------
subroutine hor_line(i_wall, walls, pt_x, pt_y, stuff)
implicit real*8 (a-h, o-z)
real*8 walls(100,5), stuff(3)
y = walls(i_wall,2)
xl = walls(i_wall,3)
xr = walls(i_wall,4)
if ((pt_x > = xl) .and. (pt_x < = xr)) then
stuff(1) = abs(y - pt_y)
stuff(2) = pt_x
else if (pt_x < xl) then
stuff(1) = sqrt((xl - pt_x)**2 + (y - pt_y)**2)
stuff(2) = xl
else
stuff(1) = sqrt((xr - pt_x)**2 + (y - pt_y)**2)
stuff(2) = xr
end if
stuff(3) = y
return
end
! --------------------------------------------
subroutine vert_line(i_wall, walls, pt_x, pt_y, stuff)
implicit real*8 (a-h, o-z)
real*8 walls(100,5), stuff(3)
x = walls(i_wall,2)
yd = walls(i_wall,3)
yu = walls(i_wall,4)
if ((pt_y > = yd) .and. (pt_y < = yu)) then
stuff(1) = abs(x - pt_x)
stuff(3) = pt_y
else if (pt_y < yd) then
stuff(1) = sqrt((x - pt_x)**2 + (yd - pt_y)**2)
stuff(3) = yd
else
stuff(1) = sqrt((x - pt_x)**2 + (yu - pt_y)**2)
stuff(3) = yu
end if
stuff(2) = x
return
end
! ---------------------------------------------
subroutine gather_data(x_pt, nr_pts, y_pt, nr_walls, walls)
implicit real*8 (a-h, o-z)
real*8 y_pt(1000) ! y scan data points
real*8 walls(100,5) ! wall data
open (3, file = 'ppt4_data.dat')
read (3,*), x_pt
nr_pts = 0
do
nr_pts = nr_pts + 1
read (3,*, end = 100) y_pt(nr_pts)
end do
100 close (3)
nr_pts = nr_pts - 1
open (3, file = 'data1.txt')
nr_walls = 0
do
nr_walls = nr_walls + 1
read (3,*, end = 200) (walls(nr_walls,j), j = 1,5)
end do
200 close (3)
nr_walls = nr_walls - 1
return
end
The FORTRAN program ppt4_ftn.f90
was written to mimic the programming of the MATLAB code.
Additional notes are as follows:
3.137.164.24