开源软件名称(OpenSource Name):benbarrowes/f2matlab开源软件地址(OpenSource Url):https://github.com/benbarrowes/f2matlab开源编程语言(OpenSource Language):开源软件介绍(OpenSource Introduction):f2matlabREADME file for f2matlab.m CONTENTS: -1. SUPPORT f2matlab AND CONSULTING 0. DISCLAIMER
-1.SUPPORT f2matlab. I now also do conversion/translation/validation/optimization consulting. Please refer to my webpage: https://sites.dartmouth.edu/barrowes/consulting/ 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@alum.mit.edu
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.5D0K(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-XX)
PM0=1.0D0
PMK=PM0
DO 20 K=1,M
PMK=(2.0D0K-1.0D0)DSQRT(X0)PM0
20 PM0=PMK
PM1=(2.0D0M+1.0D0)XPM0
PM(M)=PMK
PM(M+1)=PM1
DO 25 K=M+2,N
PM2=((2.0D0K-1.0D0)XPM1-(K+M-1.0D0)PMK)/(K-M)
PM(K)=PM2
PMK=PM1
25 PM1=PM2
PD(0)=((1.0D0-M)PM(1)-XPM(0))/(XX-1.0) 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.5D0k(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-xx) pm0=1.0D0 pmk=pm0 DO k=1,m pmk=(2.0D0k-1.0D0)DSQRT(x0)pm0 pm0=pmk END DO pm1=(2.0D0m+1.0D0)xpm0 pm(m)=pmk pm(m+1)=pm1 DO k=m+2,n pm2=((2.0D0k-1.0D0)xpm1-(k+m-1.0D0)pmk)/(k-m) pm(k)=pm2 pmk=pm1 pm1=pm2 END DO pd(0)=((1.0D0-m)pm(1)-xpm(0))/(xx-1.0) DO k=1,n pd(k)=(kxpm(k)-(k+m)pm(k-1))/(xx-1.0D0) END DO RETURN END SUBROUTINE lpmns Now we convert this to a Matlab function lpmns.m:
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:
As another example, let's follow the same procedure with dgauleg.f, a subroutine which calculates gaussian quadrature coefficients.
c---------------------------------------------------------------- INTEGER n real8 x1,x2,x(n),w(n) real8 EPS PARAMETER (EPS=3.d-14) INTEGER i,j,m real8 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.d0j-1.d0)zp2-(j-1.d0)p3)/j 11 continue pp=n(zp1-p2)/(zz-1.d0) z1=z z=z1-p1/pp end do x(i)=xm-xlz x(n+1-i)=xm+xlz w(i)=2.d0xl/((1.d0-z*z)pppp) 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 !---------------------------------------------------------------- REAL8, INTENT(IN OUT) :: x1 REAL8, INTENT(IN OUT) :: x2 REAL8, INTENT(OUT) :: x(n) REAL8, INTENT(OUT) :: w(n) INTEGER, INTENT(IN) :: n REAL8 REAL8, 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.d0j-1.d0)zp2-(j-1.d0)p3)/j END DO pp=n(zp1-p2)/(zz-1.d0) z1=z z=z1-p1/pp END DO x(i)=xm-xlz x(n+1-i)=xm+xlz w(i)=2.d0xl/((1.d0-z*z)pppp) w(n+1-i)=w(i) END DO RETURN END SUBROUTINE dgauleg And now to dgauleg.m
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:
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:
We can now try it out:
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.
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论