Home
Name Modified Size InfoDownloads / Week
f2matlab 2017-04-04
README 2017-04-04 19.5 kB
Totals: 2 Items   19.5 kB 2
README file for f2matlab.m

CONTENTS:
-1. SUPPORT f2matlab AND CONSULTING
 0. DISCLAIMER
 1. OBJECTIVE
 2. MOTIVATION
 3. BUG REPORTS and WISH LIST
 4. F2MATLAB CAPABILITIES
 5. F2MATLAB LIMITATIONS
 6. HOW TO USE F2MATLAB
 7. EXAMPLES
 8. REVISION HISTORY

-1.SUPPORT f2matlab. 
   I now also do conversion/translation/validation/optimization consulting.
   Please refer to my webpage:
   http://engineering.dartmouth.edu/~d30574x/consulting/consultingIndex.html

   Even though f2matlab is free (under GPL) for the using, I would like
   to ask that those who find it useful, wish to support the project,
   and are able to make a contribution to please do so commesurate with
   use (especially corporations). *** Important - Please donate using
   your PayPal account and not a credit card so as to avoid fees at
   PayPal. Thank you! PayPal email ID: barrowes@users.sourceforge.net


0. DISCLAIMER: Matlab is a trademark of the Mathworks company and is
   owned by them. The author makes no guarantee express or implied of
   any kind as to the applicability, usefulness, efficacy,
   bug-freeness, or the accuracy of the ensuing results from using
   f2matlab.

   The author bears no responsibility for any unwanted effect
   resulting from the use of this program. The author is not
   affiliated with the Mathworks.  The source code is given in full in
   the hopes that it will prove useful. Devlopment is done through
   sourceforge at f2matlab.sourceforge.net.

1. OBJECTIVE: f2matlab.m is a small translator which aims to
   convert Fortran90 files to Matlab m-files.

2. MOTIVATION: 

   1) Matlab is becoming ubiquitous in the engineering and scientific
   communities for its ease of use coupled with its powerful
   libraries. Yet the fact remains that a large number of stable and
   dependable programs exist in the fortran77/90 corpus. 

   2) Many times, often amidst the porting of fortran programs to
   Matlab, an automated converter of fortran90 code to Matlab code would
   be useful. 

   3) Having written matlab2fmex.m, a matlab to fortran90 mex file
   converter, the writing of f2matlab, which performs the reverse
   conversion, was substantially simplified.

3. BUG REPORTS and WISH LIST:
   For all bug reports, a wish list for f2matlab, and suggestions,
   see http://f2matlab.sourceforge.net/
   or email barrowes@users.sourceforge.net

4. F2MATLAB CAPABILITIES: f2matlab is aimed at converting 
   Fortran90 code to Matlab m-files. Accordingly, only basic data types
   and constructions are recommended. f2matlab can handle:

   all numeric types (handled by Matlab interpreter)
   most string functions
   comparisons, branches, loops, etc.
   basic read/write/print statements (if it's not too fancy...)
   modules

5. F2MATLAB LIMITATIONS: f2matlab can not handle some features of
   fortran90 yet. These include:

   can't handle complex read and write statements
   derived-typed variables
   equivalence
   ...

6. HOW TO USE F2MATLAB: f2matlab expects a single fortran90 fortran file to
   convert. If you have fortran77 code, use some free converter
   (e.g. to_f90 by Alan Miller) before running f2matlab. Then simply
   call f2matlab by using the full filename:
   f2matlab('filename.f90');
   The output will be filename.m in the same directory.
   
   A few flags are available that effect conversion:
   %  want_kb=0; 1 ==> if keyboard mode is desired after some conversion steps
   %  want_ze=0; 1 ==> direct f2matlab to zero all array variables.
   %  want_fi=0; 1 ==> direct f2matlab to try to put fix()'s around declared integers.

   Multiple subroutines and functions can and should be in the same fortran90 file.

7. EXAMPLES:
   Below are some specific examples. Other tests and examples include:
   
   Running the script TESTING_cfs in the comp_spec_func directory converts all of the f90
   code from Shanjie Zhang and Jianming Jin's book. These converted m-files can also be found
   at: http://ceta.mit.edu/comp_spec_func/

   For some larger examples (>=10000 lines), see the examples directory. The following
   fortran packages were downloaded (most from John Burkardt at FSU) and converted:

   - fempack routines for finite element analysis:
     f2matlab('femprb.f90');

   - quadrule
     f2matlab('quadrule_prb.f90');

   - quadrature integration routines by Arthur Stroud:
     f2matlab('stroud_prb.f90');


     Run the script TESTING_ex in the examples directory to convert and test all the examples
     there.



   The following f77 program, lpmns.f, calculates the associated legendre
   function for degree m, order n, and parameter x. The output is the function value pm
   and the value of the derivative pd. This function is from the book "Computation of
   Special Functions." by Shanjie Zhang, and Jianming Jin, New York : Wiley, c1996.

   These examples are in the examples directory.

       SUBROUTINE LPMNS(M,N,X,PM,PD)
c**************************************************************
C
C       ========================================================
C       Purpose: Compute associated Legendre functions Pmn(x)
C                and Pmn'(x) for a given order
C       Input :  x --- Argument of Pmn(x)
C                m --- Order of Pmn(x),  m = 0,1,2,...,n
C                n --- Degree of Pmn(x), n = 0,1,2,...,N
C       Output:  PM(n) --- Pmn(x)
C                PD(n) --- Pmn'(x)
C       ========================================================
C
        IMPLICIT DOUBLE PRECISION (A-H,O-Z)
        DIMENSION PM(0:N),PD(0:N)
        DO 10 K=0,N
           PM(K)=0.0D0
10         PD(K)=0.0D0
        IF (DABS(X).EQ.1.0D0) THEN
           DO 15 K=0,N
              IF (M.EQ.0) THEN
                 PM(K)=1.0D0
                 PD(K)=0.5D0*K*(K+1.0)
                 IF (X.LT.0.0) THEN
                    PM(K)=(-1)**K*PM(K)
                    PD(K)=(-1)**(K+1)*PD(K)
                 ENDIF
              ELSE IF (M.EQ.1) THEN
                 PD(K)=1.0D+300
              ELSE IF (M.EQ.2) THEN
                 PD(K)=-0.25D0*(K+2.0)*(K+1.0)*K*(K-1.0)
                 IF (X.LT.0.0) PD(K)=(-1)**(K+1)*PD(K)
              ENDIF
15         CONTINUE
           RETURN
        ENDIF
        X0=DABS(1.0D0-X*X)
        PM0=1.0D0
        PMK=PM0
        DO 20 K=1,M
           PMK=(2.0D0*K-1.0D0)*DSQRT(X0)*PM0
20         PM0=PMK
        PM1=(2.0D0*M+1.0D0)*X*PM0
        PM(M)=PMK
        PM(M+1)=PM1
        DO 25 K=M+2,N
           PM2=((2.0D0*K-1.0D0)*X*PM1-(K+M-1.0D0)*PMK)/(K-M)
           PM(K)=PM2
           PMK=PM1
25         PM1=PM2
        PD(0)=((1.0D0-M)*PM(1)-X*PM(0))/(X*X-1.0)  
        DO 30 K=1,N
30          PD(K)=(K*X*PM(K)-(K+M)*PM(K-1))/(X*X-1.0D0)
        RETURN
        END

As this is fortran77, we use to_f90 to get lpmns.f90:

SUBROUTINE lpmns(m,n,x,pm,pd)
 
! Code converted using TO_F90 by Alan Miller
! Date: 2002-05-14  Time: 13:32:33
 
!**************************************************************

!       ========================================================
!       Purpose: Compute associated Legendre functions Pmn(x)
!                and Pmn'(x) for a given order
!       Input :  x --- Argument of Pmn(x)
!                m --- Order of Pmn(x),  m = 0,1,2,...,n
!                n --- Degree of Pmn(x), n = 0,1,2,...,N
!       Output:  PM(n) --- Pmn(x)
!                PD(n) --- Pmn'(x)
!       ========================================================


INTEGER, INTENT(IN)                      :: m
INTEGER, INTENT(IN)                      :: n
DOUBLE PRECISION, INTENT(IN)             :: x
DOUBLE PRECISION, INTENT(OUT)            :: pm(0:n)
DOUBLE PRECISION, INTENT(OUT)            :: pd(0:n)
IMPLICIT DOUBLE PRECISION (a-h,o-z)


DO  k=0,n
  pm(k)=0.0D0
  pd(k)=0.0D0
END DO
IF (DABS(x) == 1.0D0) THEN
  DO  k=0,n
    IF (m == 0) THEN
      pm(k)=1.0D0
      pd(k)=0.5D0*k*(k+1.0)
      IF (x < 0.0) THEN
        pm(k)=(-1)**k*pm(k)
        pd(k)=(-1)**(k+1)*pd(k)
      END IF
    ELSE IF (m == 1) THEN
      pd(k)=1.0D+300
    ELSE IF (m == 2) THEN
      pd(k)=-0.25D0*(k+2.0)*(k+1.0)*k*(k-1.0)
      IF (x < 0.0) pd(k)=(-1)**(k+1)*pd(k)
    END IF
  END DO
  RETURN
END IF
x0=DABS(1.0D0-x*x)
pm0=1.0D0
pmk=pm0
DO  k=1,m
  pmk=(2.0D0*k-1.0D0)*DSQRT(x0)*pm0
  pm0=pmk
END DO
pm1=(2.0D0*m+1.0D0)*x*pm0
pm(m)=pmk
pm(m+1)=pm1
DO  k=m+2,n
  pm2=((2.0D0*k-1.0D0)*x*pm1-(k+m-1.0D0)*pmk)/(k-m)
  pm(k)=pm2
  pmk=pm1
  pm1=pm2
END DO
pd(0)=((1.0D0-m)*pm(1)-x*pm(0))/(x*x-1.0)
DO  k=1,n
  pd(k)=(k*x*pm(k)-(k+m)*pm(k-1))/(x*x-1.0D0)
END DO
RETURN
END SUBROUTINE lpmns

Now we convert this to a Matlab function lpmns.m:

>> f2matlab('lpmns.f90');
  subroutine lpmns(m,n,x,pm,pd)
    Number of lines:   70
      Writing file:  lpmns.m ... completed 
  Total time: 0.58333
>> 

Resulting in lpmns.m:

function [m,n,x,pm,pd]=lpmns(m,n,x,pm,pd);

%**************************************************************

%       ========================================================
%       Purpose: Compute associated Legendre functions Pmn(x)
%                and Pmn'(x) for a given order
%       Input :  x --- Argument of Pmn(x)
%                m --- Order of Pmn(x),  m = 0,1,2,...,n
%                n --- Degree of Pmn(x), n = 0,1,2,...,N
%       Output:  PM(n) --- Pmn(x)
%                PD(n) --- Pmn'(x)
%       ========================================================


for  k=0:n;
pm(k+1)=0.0d0;
pd(k+1)=0.0d0;
end;
if (abs(x) == 1.0d0);
for  k=0:n;
if (m == 0);
pm(k+1)=1.0d0;
pd(k+1)=0.5d0.*k.*(k+1.0);
if (x < 0.0);
pm(k+1)=(-1).^k.*pm(k+1);
pd(k+1)=(-1).^(k+1).*pd(k+1);
end;
elseif (m == 1);
pd(k+1)=1.0d+300;
elseif (m == 2);
pd(k+1)=-0.25d0.*(k+2.0).*(k+1.0).*k.*(k-1.0);
if (x < 0.0) pd(k+1)=(-1).^(k+1).*pd(k+1); end;
end;
end;
return;
end;
x0=abs(1.0d0-x.*x);
pm0=1.0d0;
pmk=pm0;
for  k=1:m;
pmk=(2.0d0.*k-1.0d0).*sqrt(x0).*pm0;
pm0=pmk;
end;
pm1=(2.0d0.*m+1.0d0).*x.*pm0;
pm(m+1)=pmk;
pm(m+1+1)=pm1;
for  k=m+2:n;
pm2=((2.0d0.*k-1.0d0).*x.*pm1-(k+m-1.0d0).*pmk)./(k-m);
pm(k+1)=pm2;
pmk=pm1;
pm1=pm2;
end;
pd(0+1)=((1.0d0-m).*pm(1+1)-x.*pm(0+1))./(x.*x-1.0);
for  k=1:n;
pd(k+1)=(k.*x.*pm(k+1)-(k+m).*pm(k-1+1))./(x.*x-1.0d0);
end;




Now we can run lpmns.m:

>> [a1,a2,a3,pm,pd]=lpmns(0,10,.5)
a1 =
     0
a2 =
    10
a3 =
                       0.5
pm =
  Columns 1 through 4 
                         1                       0.5                    -0.125                   -0.4375
  Columns 5 through 8 
                -0.2890625                0.08984375              0.3232421875             0.22314453125
  Columns 9 through 11 
        -0.073638916015625        -0.267898559570312        -0.188228607177734
pd =
  Columns 1 through 4 
                         0                         1                       1.5                     0.375
  Columns 5 through 8 
                   -1.5625                -2.2265625               -0.57421875              1.9755859375
  Columns 9 through 11 
             2.77294921875         0.723724365234375         -2.31712341308594
>> 

Incidentally, it is now possible to convert lpmns.m into a fortran90
mex file callable from Matlab using matlab2fmex.m.
(See http://matlab2fmex.sourceforge.net/ )
First, construct another input which is the same size as the
output. Here is the modified lpmns2.m

function [pm,pd]=lpmns(m,n,x,outsize)

%**************************************************************

%       ========================================================
%       Purpose: Compute associated Legendre functions Pmn(x)
%                and Pmn'(x) for a given order
%       Input :  x --- Argument of Pmn(x)
%                m --- Order of Pmn(x),  m = 0,1,2,...,n
%                n --- Degree of Pmn(x), n = 0,1,2,...,N
%       Output:  PM(n) --- Pmn(x)
%                PD(n) --- Pmn'(x)
%       ========================================================

for  k=0:n;
 pm(k+1)=0.0d0;
 pd(k+1)=0.0d0;
end;
if (abs(x) == 1.0d0);
 for  k=0:n;
  if (m == 0);
   pm(k+1)=1.0d0;
   pd(k+1)=0.5d0.*k.*(k+1.0);
   if (x < 0.0);
    pm(k+1)=(-1).^k.*pm(k+1);
    pd(k+1)=(-1).^(k+1).*pd(k+1);
   end;
  elseif (m == 1);
   pd(k+1)=1.0d+300;
  elseif (m == 2);
   pd(k+1)=-0.25d0.*(k+2.0).*(k+1.0).*k.*(k-1.0);
   if (x < 0.0)
    pd(k+1)=(-1).^(k+1).*pd(k+1);
   end;
  end;
 end;
 return;
end;
x0=abs(1.0d0-x.*x);
pm0=1.0d0;
pmk=pm0;
for  k=1:m;
 pmk=(2.0d0.*k-1.0d0).*sqrt(x0).*pm0;
 pm0=pmk;
end;
pm1=(2.0d0.*m+1.0d0).*x.*pm0;
pm(m+1)=pmk;
pm(m+1+1)=pm1;
for  k=m+2:n;
 pm2=((2.0d0.*k-1.0d0).*x.*pm1-(k+m-1.0d0).*pmk)./(k-m);
 pm(k+1)=pm2;
 pmk=pm1;
 pm1=pm2;
end;
pd(0+1)=((1.0d0-m).*pm(1+1)-x.*pm(0+1))./(x.*x-1.0);
for  k=1:n;
 pd(k+1)=(k.*x.*pm(k+1)-(k+m).*pm(k-1+1))./(x.*x-1.0d0);
end;

Now create a lpmns.mat file using matlab2fmex_save:

>> n=10;matlab2fmex_save('[x,w]=lpmns2(0,n,.5,zeros(1,n+1));');

And now convert lpmns.m to a fortran90 mex file:

>> matlab2fmex('lpmns2');
Converting --- lpmns2.m  ==>  lpmns2.f  ==>  lpmns2.mex
matlab2fmex.
 ==> mex lpmns2.f mexfunctions.f mexoperators.f mexcallback.f 
>> 

Finally, we can call lpmns2 as a mex file from the Matlab command
prompt: 

>> [pm,pd]=lpmns2(0,n,.5,zeros(1,n+1))
pm =
  Columns 1 through 3 
                         1                       0.5                    -0.125
  Columns 4 through 6 
                   -0.4375                -0.2890625                0.08984375
  Columns 7 through 9 
              0.3232421875             0.22314453125        -0.073638916015625
  Columns 10 through 11 
        -0.267898559570312        -0.188228607177734
pd =
  Columns 1 through 3 
                         0                         1                       1.5
  Columns 4 through 6 
                     0.375                   -1.5625                -2.2265625
  Columns 7 through 9 
               -0.57421875              1.9755859375             2.77294921875
  Columns 10 through 11 
         0.723724365234375         -2.31712341308594
>> 
>> which lpmns2
/home/barrowes/compiler/f2matlab/examples/lpmns2.mexaxp
>> 

We have just converted a native fortran77 subroutine into a fortran90
mex file usable (with variable sized inputs) in Matlab.


lqmns.f in the examples directory can be handles similarly.


As another example, let's follow the same procedure with dgauleg.f, a
subroutine which calculates gaussian quadrature coefficients.

      SUBROUTINE dgauleg(x1,x2,x,w,n)
c----------------------------------------------------------------
      INTEGER n
      real*8 x1,x2,x(n),w(n)
      real*8 EPS
      PARAMETER (EPS=3.d-14)
      INTEGER i,j,m
      real*8 p1,p2,p3,pp,xl,xm,z,z1
      m=(n+1)/2
      z1=huge(1.0)
      xm=0.5d0*(x2+x1)
      xl=0.5d0*(x2-x1)
      do 12 i=1,m
        z=cos(3.141592654d0*(i-.25d0)/
     & (n+.5d0))
        do while (abs(z-z1).gt.EPS)
         p1=1.d0
         p2=0.d0
         do 11 j=1,n
          p3=p2
          p2=p1
          p1=((2.d0*j-1.d0)*z*p2-(j-1.d0)*p3)/j
 11      continue
         pp=n*(z*p1-p2)/(z*z-1.d0)
         z1=z
         z=z1-p1/pp
        end do
        x(i)=xm-xl*z
        x(n+1-i)=xm+xl*z
        w(i)=2.d0*xl/((1.d0-z*z)*pp*pp)
        w(n+1-i)=w(i)
12    continue
      return
      end

Now convert to fortran90

SUBROUTINE dgauleg(x1,x2,x,w,n)
 
! Code converted using TO_F90 by Alan Miller
! Date: 2002-05-14  Time: 13:40:52
 
!----------------------------------------------------------------

REAL*8, INTENT(IN OUT)                   :: x1
REAL*8, INTENT(IN OUT)                   :: x2
REAL*8, INTENT(OUT)                      :: x(n)
REAL*8, INTENT(OUT)                      :: w(n)
INTEGER, INTENT(IN)                      :: n


REAL*8
REAL*8, PARAMETER :: eps=3.d-14
INTEGER :: i,j,m
REAL*8 p1,p2,p3,pp,xl,xm,z,z1

m=(n+1)/2
z1=huge(1.0)
xm=0.5D0*(x2+x1)
xl=0.5D0*(x2-x1)
DO  i=1,m
  z=COS(3.141592654D0*(i-.25D0)/ (n+.5D0))
  DO WHILE (ABS(z-z1) > eps)
    p1=1.d0
    p2=0.d0
    DO  j=1,n
      p3=p2
      p2=p1
      p1=((2.d0*j-1.d0)*z*p2-(j-1.d0)*p3)/j
    END DO
    pp=n*(z*p1-p2)/(z*z-1.d0)
    z1=z
    z=z1-p1/pp
  END DO
  x(i)=xm-xl*z
  x(n+1-i)=xm+xl*z
  w(i)=2.d0*xl/((1.d0-z*z)*pp*pp)
  w(n+1-i)=w(i)
END DO
RETURN
END SUBROUTINE dgauleg

And now to dgauleg.m

>> f2matlab('dgauleg.f90');
  subroutine dgauleg(x1,x2,x,w,n)
    Number of lines:   44
  No Matlab function for 'huge' except replacing with 'realmax' in Matlab
    Writing file:  dgauleg.m ... completed 
  Total time: 0.35
>> 

Resulting dgauleg.m:

function [x1,x2,x,w,n]=dgauleg(x1,x2,x,w,n);

%----------------------------------------------------------------

eps=3.d-14;

m=(n+1)./2;
z1=realmax(1.0);
xm=0.5d0.*(x2+x1);
xl=0.5d0.*(x2-x1);
for  i=1:m;
z=cos(3.141592654d0.*(i-.25d0)./ (n+.5d0));
while (abs(z-z1) > eps);
p1=1.d0;
p2=0.d0;
for  j=1:n;
p3=p2;
p2=p1;
p1=((2.d0.*j-1.d0).*z.*p2-(j-1.d0).*p3)./j;
end;
pp=n.*(z.*p1-p2)./(z.*z-1.d0);
z1=z;
z=z1-p1./pp;
end;
x(i)=xm-xl.*z;
x(n+1-i)=xm+xl.*z;
w(i)=2.d0.*xl./((1.d0-z.*z).*pp.*pp);
w(n+1-i)=w(i);
end;


And now we can call it from Matlab:
>>  [x,w]=dgauleg(0,1,0,1,10)  
x =
     0
w =
     1
>>  [x1,x2,x,w,n]=dgauleg(0,1,0,1,10)
x1 =
     0
x2 =
     1
x =
  Columns 1 through 4 
        0.0130467357414142        0.0674683166555077         0.160295215850488         0.283302302935376
  Columns 5 through 8 
         0.425562830509184         0.574437169490816         0.716697697064624         0.839704784149512
  Columns 9 through 10 
         0.932531683344492         0.986953264258586
w =
  Columns 1 through 4 
        0.0333356721543414        0.0747256745752903         0.109543181257991         0.134633359654996
  Columns 5 through 8 
         0.147762112357376         0.147762112357376         0.134633359654996         0.109543181257991
  Columns 9 through 10 
        0.0747256745752903        0.0333356721543414
n =
    10
>> 


Finally, here is an example which converts a fortran90 program with subroutines into
Matlab. The program is MCPBDN.for from the book "Computation of Special Functions." by
Shanjie Zhang, and Jianming Jin, New York : Wiley, c1996. After using to_f90 on this file,
the only alteration was to specify the inputs x and y in the code instead of using a read
statement. See the /examples directory.

Converting:
>> f2matlab('mcpbdn.f90');
  program mcpbdn
    Number of lines:   61
  subroutine cpbdn(n,z,cpb,cpd)
    Number of lines:   103
  subroutine cpdsa(n,z,cdn)
    Number of lines:   57
  subroutine cpdla(n,z,cdn)
    Number of lines:   30
  subroutine gaih(x,ga)
    Number of lines:   29
    Writing file:  mcpbdn.m ... completed 
  Total time: 2.75
>> 

We can now try it out:

>> mcpbdn
ans =
please enter n, x and y 
ans =
  n     re[dn(z)]       im[dn(z)]       
ans =
re[dn'(z)]      im[dn'(z)]
ans =
-------------------------------------------
ans =
-------------------------
i =
     0
ans =
          0.997798279178581 +    0.0663218973512007i
ans =
          -2.32869095456845 -      2.66030044132445i
i =
     1
ans =
            4.6573819091369 +      5.32060088264891i
ans =
            2.6558457129586 -      24.8786350821133i
i =
     2
ans =
          -4.31389314673862 +      49.8235920615778i
ans =
           144.658476839065 -        103.1330455218i
i =
     3
ans =
          -280.002189859856 +      216.907292808898i
ans =
           1229.33202723167 +      307.208018812128i
i =
     4
ans =
          -2471.60573390356 -      464.945261439523i
ans =
           3896.64242172066 +      8209.00665959329i
i =
     5
ans =
          -8913.29360288074 -       15550.384147951i
ans =
          -28950.7550321934 +      58834.4680698817i
>> 

Which agrees with the values produced by the original code.



8. REVISION HISTORY:
   See changelog
Source: README, updated 2017-04-04