0
votes

I have the exact same code written in Fortran and Matlab. The code runs serially in both languages fine, but is substantially faster in Fortran. One of the loops of the code can be parallelized. In Matlab I achieve this very easily by just replacing a for with parfor.

Is there any such easy to it in Fortran? I am using Intel Fortran to compile the code.

Here is a very simple example of what I am doing:

Matlab code:

clear;
tic

gamma=5; 
beta=0.95;
T=5; 
r=0.015; 
maxw = 50;
minw = 1;
nw = 50;
nc = 50;
gw = linspace(minw,maxw,nw)';
gc = linspace(0.0,maxw,nc)';

c = zeros(nw,T);
v = zeros(nw,T);

c(:,T)=gw(:,1);
v(:,T) = (c(:,T).^(1-gamma))/(1-gamma);

for i=T-1:-1:1,
    i
    aux = v(:,i+1);
    parfor z=1:nw,
        auxV=zeros(nc,1);
        for j=1:nc,
            sav = gw(z,1)-gc(j,1);
            w_t1 = (1+r)*sav;
            w_t1 = max(min(w_t1,maxw),minw); 
            auxV(j,1)=(gc(j,1)^(1-gamma))/(1-gamma)+beta*interpn(gw,aux,w_t1);
        end 
        [v(z,i) imax]= max(auxV);
        c(z,i)=gc(imax,1);
    end 
end 
toc

With that parfor on the syntax computational time reduces significantly.

And equivalent fortran code is:

PROGRAM toy
IMPLICIT NONE


REAL :: gamma=5; 
REAL :: beta=0.95; 
INTEGER :: T=5; 
REAL :: r=0.015; 
REAL :: maxw = 50;
REAL :: minw = 1;
INTEGER :: nw = 50;
REAL, DIMENSION(1,50) :: gw, gc, aux3
REAL, DIMENSION(50,1) :: secd
INTEGER :: ind1, ind2, ind3

INTEGER :: nc = 50;
REAL, DIMENSION(50,5) :: c, v
REAL, DIMENSION(50,1) :: aux, auxV
REAL :: sav, w_t1
INTEGER, DIMENSION(1,1) :: pt
REAL :: aux1

c = 0;
v = 0;

DO ind1=1,nw
   gw(1,ind1)=1.0+(ind1-1.0)*1.0
END DO

DO ind1=1,nc
   gc(1,ind1)=0.0+(ind1-1.0)*1.0
END DO

aux3(1,:) = gw(1,:)

c(:,T)=gw(1,:);
v(:,T) = (c(:,T)**(1-gamma))/(1-gamma);


do ind1=T-1,1,-1

    secd(:,1) = 0.0
    call spline(aux3,v(:,ind1+1),nw,gamma,secd(:,1)) 

    aux(:,1) = v(:,ind1+1)
    do ind3=1,nw

        auxV=0; 

        do ind2=1,nc
            sav = gw(1,ind3)-gc(1,ind2);
            w_t1 = (1+r)*sav;

            w_t1 = max(min(w_t1,maxw),minw) 

            call splint(aux3,v(:,ind1+1),secd(:,1),nw,w_t1,1,1,aux1)
            auxV(ind2,1)=(gc(1,ind2)**(1-gamma))/(1-gamma)+beta*aux1
        end do

        v(ind3,ind1) = maxval(auxV)
        pt(1,1) = sum(maxloc(auxV))
        c(ind3,ind1)=gc(1,pt(1,1))
    end do
end do

end program

Is there any simple way to parallelize that second nested loop just like the matlab?

2
Why is it relevant that you have MATLAB code? Please try to limit your question to the relevant information. - Daniel
You MUST post the code. If it is huge, post the relevant part. If you are concerned about one particular loop, post that one. Also, have you tried to read or search anything about parallel processing in Fortran? There are tons of resources about that on Stack Overflow. - Vladimir F
Fortram is a lower level programming paradigm than MATLAB, meaning that good Fortram code will most likely always be faster than MATLAB, but also it will most likely always be harder to write. - Ander Biguri
@VladimirF, just updated the question with some code. - phdstudent

2 Answers

1
votes

Most current Fortran compilers support OpenMP. This is similar to Matlab Parfor, but not quite as easy to use. Suggest you try OpenMP, it should give you a similar speed increase to the speed increase you find with parfor. OpenMP is well documented and very solid.

1
votes
ifort toy.f90 -parallel

Maybe not as good as the other options like coarrays or others but give it a try, super easy to implement!