I/O in pure Fortran procedures

萝らか妹 提交于 2019-12-23 08:50:43

问题


I'm trying to incorporate error checking within a pure procedure I am writing. I would like something like:

pure real function func1(output_unit,a)
    implicit none
    integer :: a, output_unit

    if (a < 0) then
        write(output_unit,*) 'Error in function func1: argument must be a nonnegative integer. It is ', a
    else
    func1 = a/3

    endif
    return
end function func1

However, pure functions are not allowed to have IO statements to external files, so I tried passing a unit number to the function, e.g. output_unit = 6, which is the default output. gfortran still regards this as illegal. Is there a way around this? Is it possible to make the function a derived type (instead of intrinsic type real here) which outputs a string when there is an error?


回答1:


You are not the first person to have this problem, and I'm happy to say that this flaw in the standard will be remedied in Fortran 2015. As stated in this document (page 6, header "Approved changes to the standard"), "the restriction on the appearance of an error stop statement in a pure procedure should be removed".

The Fortran 2008 standard included the error stop statement in the context of some new parallel computing features. It signals an error and makes all processes stop as soon as is practicable. Currently, neither stop nor error stop statements are allowed in pure procedures, because they're obviously not thread-safe. In practice this is unnecessarily restrictive in cases where an internal error occurs.

Depending on your compiler, you may have to wait patiently for the implementation. I know that Intel has implemented it in their ifort compiler. ("F2015: Lift restriction on STOP and ERROR STOP in PURE/ELEMENTAL procedures")

alternative

For an alternative approach, you could have a look at this question, though in you case this is probably slightly trickier as you have to change the do concurrent keyword, not just pure.

(end of proper answer)

if getting dirty hands is an option ...

In the meantime you could do something brutal like

pure subroutine internal_error(error_msg)
    ! Try hard to produce a runtime error, regardless of compiler flags.
    ! This is useful in pure subprograms where you want to produce an error, 
    ! preferably with a traceback.
    ! 
    ! Though far from pretty, this solution contains all the ugliness in this 
    ! single subprogram.
    ! 
    ! TODO: replace with ERROR STOP when supported by compiler
    implicit none

    character(*), intent(in) :: error_msg

    integer, dimension(:), allocatable :: molested

    allocate(molested(2))
    allocate(molested(2))
    molested(3) = molested(4)
    molested(1) = -10
    molested(2) = sqrt(real(molested(1)))
    deallocate(molested)
    deallocate(molested)
    molested(3) = molested(-10)
end subroutine internal_error

Should anyone ask, you didn't get this from me.




回答2:


I've found an answer myself, detailed here. It uses what is considered "obsolescent", but still does the trick; it is called alternate return. Write the procedure as a subroutine as it doesn't work on functions.

pure real subroutine procA(arg1)
    implicit none
    integer :: arg1

    if (arg < 0) then
        return 1 ! exit the function and go to the first label supplied
                 ! when function was called. Also return 2, 3 etc.
    else
        procA = ... ! whatever it should do under normal circumstances
    endif
endsubroutine procA

.... 

! later on, procedure is called
num = procA(a, *220)

220 write(6,*) 'Error with func1: you've probably supplied a negative argument'

What would probably be better is what eriktous suggested--get the procedure to return a status, perhaps as a logical value or an integer, and get the program to check this value every time after it calls the procedure. If all's well, carry on. Otherwise, print a relevant error message.

Comments welcome.



来源:https://stackoverflow.com/questions/8767206/i-o-in-pure-fortran-procedures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!