从Fortran模块中定义的函数打印到标准输出

时间:2014-07-24 00:07:49

标签: fortran

我正在努力学习Fortran(遗憾的是我的研究小组的必要性) - 我自己设定的任务之一是将一个必要的函数(Associated Legendre多项式)从Numerical Recipes一书打包成fortran 03模块。原始程序(f77)以下列形式进行了一些错误处理:

if(m.lt.0.or.m.gt.1.or.abs(x).gt.1)pause 'bad arguments in plgndr'

自从f77以来,暂停似乎已被弃用,因为使用此行会给我一个编译错误,所以我尝试了以下内容:

module sha_helper
    implicit none
    public :: plgndr, factorial!, ylm

contains
    ! numerical recipes Associated Legendre Polynomials rewritten for f03
    function plgndr(l,m,x) result(res_plgndr)
        integer, intent(in) :: l, m
        real, intent(in) :: x
        real :: res_plgndr, fact, pll, pmm, pmmp1, somx2
        integer ::  i,ll
        if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then 
            write (*, *) "bad arguments to plgndr, aborting", m, x
            res_plgndr=-10e6 !return a ridiculous value
        else
            pmm = 1.
            if (m.gt.0) then
                somx2 = sqrt((1.-x)*(1.+x))
                fact = 1.
                do i = 1, m
                    pmm = -pmm*fact*somx2
                    fact = fact+2
                end do
            end if
            if (l.eq.m) then
                res_plgndr = pmm
            else
                pmmp1 = x*(2*m+1)*pmm
                if(l.eq.m+1) then
                    res_plgndr = pmmp1
                else
                    do ll = m+2, l
                        pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m)
                        pmm = pmmp1
                        pmmp1 = pll
                    end do
                    res_plgndr = pll
                end if
            end if
        end if
    end function plgndr

    recursive function factorial(n) result(factorial_result)
        integer, intent(in) :: n
        integer, parameter :: RegInt_K = selected_int_kind(20) !should be enough for the factorials I am using
        integer (kind = RegInt_K) :: factorial_result
        if (n <= 0) then
            factorial_result = 1
        else 
            factorial_result = n * factorial(n-1)
        end if 
    end function factorial

!     function ylm(l,m,theta,phi) result(res_ylm)
!         integer, intent(in) :: l, m
!         real, intent(in) :: theta, phi
!         real :: res_ylm, front_block
!         real, parameter :: pi = 3.1415926536
!         front_block = sqrt((2*l+1)*factorial(l-abs(m))/(4*pi*))
!     end function ylm

end module sha_helper

else之后的主代码工作,但如果我执行我的主程序并调用具有错误值的函数,程序会在执行print语句之前冻结。我知道print语句是问题,因为将其注释掉允许函数正常执行,返回-10e6作为值。理想情况下,我希望程序在给出用户可读的错误消息后崩溃,因为为plgndr函数赋予错误值是程序的致命错误。函数plgndr由程序sha_lmc使用。目前所有这一切都是读取一些数组,然后打印plgndr值进行测试(早期)。模块sha_helper中的函数ylm也没有完成,因此它被注释掉了。代码使用gfortran sha_helper.f03 sha_lmc.f03 -o sha_lmc进行编译, gfortran --version GNU Fortran(GCC)4.8.2

!Spherical Harmonic Bayesian Analysis testbed for Lagrangian Dynamical Monte Carlo

program sha_analysis
use sha_helper
implicit none
!Analysis Parameters
integer, parameter :: harm_order = 6
integer, parameter :: harm_array_length = (harm_order+1)**2
real, parameter :: coeff_lo = -0.1, coeff_hi = 0.1, data_err = 0.01 !for now, data_err fixed rather than heirarchical
!Monte Carlo Parameters
integer, parameter :: run = 100000, burn = 50000, thin = 100
real, parameter :: L = 1.0, e = 1.0

!Variables needed by the program
integer :: points, r, h, p, counter = 1
real, dimension(:), allocatable :: x, y, z 
real, dimension(harm_array_length) :: l_index_list, m_index_list
real, dimension(:,:), allocatable :: g_matrix

!Open the file, allocate the x,y,z arrays and read the file
open(1, file = 'Average_H_M_C_PcP_boschi_1200.xyz', status = 'old')
read(1,*) points
allocate(x(points))
allocate(y(points))
allocate(z(points))
print *, "Number of Points: ", points
readloop: do r = 1, points
    read(1,*) x(r), y(r), z(r)
end do readloop

!Set up the forwards model
allocate(g_matrix(harm_array_length,points))
!Generate the l and m values of spherical harmonics
hloop: do h = 0, harm_order
    ploop: do p = -h,h
        l_index_list(counter) = h
        m_index_list(counter) = p
        counter = counter + 1
    end do ploop
end do hloop

print *, plgndr(1,2,0.1)
!print *, ylm(1,1,0.1,0.1)


end program sha_analysis

2 个答案:

答案 0 :(得分:6)

您的程序执行所谓的递归IO - 对plgndr的初始调用位于IO语句的输出项列表中(打印语句)[将输出定向到控制台] - 然后在该函数内部还尝试执行另一个IO语句[输出到控制台]。这是不允许的 - 见F2003的9.11p2和p3或F2008的9.12p2。

解决方案是将函数调用与主程序中的io语句分开,即

REAL :: a_temporary
...
a_temporary = plgndr(1,2,0.1)
PRINT *, a_temporary

F2008中的其他替代方案(但不是F2003 - 因此第一段中的[]部分)包括将函数的输出定向到不同的逻辑单元(请注意WRITE (*, ...PRINT ...引用同一单位)。

在F2008中,您还可以将WRITE语句替换为带有消息的STOP语句(该消息必须是常量 - 这不会让您报告有问题的值)。

无意中调用递归IO的可能性是某些编程风格不鼓励在函数中执行IO的部分原因。

答案 1 :(得分:0)

尝试:

if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
   write (*, *) "bad arguments to plgndr, aborting", m, x
   stop
else
   ...
end if