gfortran compiler error calling recursive log_gamma function - fortran

I uploaded a 2F1 hypergeometric function but it turns out that it does not compile on my computer. It is from this article. I use
GNU Fortran (Built by Jeroen for the R-project) 8.3.0
shiped with RTools 4.0. Can you figure out why it does not compile and how this could be solved? In the code below, I just kept the one line that generates the error. The error is given next.
MODULE HYP_2F1_MODULE
!--------------------------------------------------------------------
IMPLICIT NONE
INTEGER, PARAMETER :: PR=KIND(1.0D0)
REAL(PR) :: ONE=1.0D0
CONTAINS
!
END MODULE HYP_2F1_MODULE
!
!----------------------------------------------------------------------
RECURSIVE FUNCTION LOG_GAMMA(Z) RESULT(RES)
USE HYP_2F1_MODULE
IMPLICIT NONE
COMPLEX(PR),INTENT(IN) :: Z
COMPLEX(PR) :: RES
!
RES = LOG_GAMMA( ONE -z);
!
END FUNCTION LOG_GAMMA
Here is the error message
testZ.f90:18:22:
RES = LOG_GAMMA( ONE - Z);
1
Error: 'x' argument of 'log_gamma' intrinsic at (1) must be REAL

There is a Fortran 2008+ intrinsic of the same name
16.9.119 LOG_GAMMA (X)
1 Description. Logarithm of the absolute value of the gamma function.
2 Class. Elemental function.
3 Argument. X
shall be of type real. Its value shall not be a negative integer or
zero.
There is some sort of clash I do not completely understand here. The obvious workaround is to rename your function. What I can say is that without the result clause (which you need because of the recursive attribute) the intrinsic would be shadowed. It might be a compiler bug.
Also consider, whether the intrinsic of the same name couldn't also do what you need from your function.

In addition to #VladimirF's suggestions, you can add the compiler flag -std=f95 to enforce compliance with the Fortran 95 standard. Provided you haven't added -fall-intrinsics this will disable all intrinsics from standards after Fortran 95, and should make the legacy code work.

Related

Dummy argument associated actual procedure differs from dummy argument of the dummy procedure

I'm using a the function NEQNF from the IMSL Fortran Library to solve a non-linear equation system and get 3 errors. I'm using Visual Studio 2017 on a x64 system. The error says the following:
Error #7061: The characterístic of dummy argument 1 of the associated actual procedure differ from the characteristics of dummy argument 1 of the dummy procedure [FCN_SS]
Error #7062: The characterístic of dummy argument 2 of the associated actual procedure differ from the characteristics of dummy argument 2 of the dummy procedure [FCN_SS]
Error #7063: The characterístic of dummy argument 3 of the associated actual procedure differ from the characteristics of dummy argument 3 of the dummy procedure [FCN_SS]
The code is:
include 'link_fnl_shared.h'
use neqnf_int
use umach_int
implicit none
!Declaring variables
.
.
.
Contains
subroutine solve_ss(x, fnorm)
integer n
parameter (n=2)
integer k, nout
real(dp) :: fnorm, x(n), xguess(n)
data xguess/1.0_dp, 0.3_dp/ !guess for total output in units
call umach (2, nout)
call neqnf (fcn_ss, x, xguess=xguess, fnorm=fnorm)
end subroutine solve_ss
subroutine fcn_ss(x, f, n)
implicit none
!specification
integer n
real(dp) :: x(n), f(n)
.
.
.
F(1)=...
F(2)=...
end subroutine fcn_ss
I'm not sure what the error is about, since the declaration of the variables is the same in solve_ss and fcn_ss.
The documentation of the library explicitly states (here and here) that you are required to use the respective modules in order to have access to modern implementation of the routines.
Otherwise, you may be (I can't test, but I'm basing on this) accessing legacy support of the library. So, instead of the generic Fortran 90 interface, It may be leading you to the FORTRAN77 specific interface:
NEQNF (FCN, ERRREL, N, ITMAX, XGUESS, X, FNORM)
Other detail is that the documentation explicity states you must declare the passed function as external:
external fcn_ss
Still, I'm not sure about those guesses. Could be that or any other strange error. Please provide feedback.

Error with parentheses when assigning to complex variable

I have the following set of commands in my Fortran code:
COMPLEX*16, DIMENSION(4,1) :: INSTATE_BASISSTATES
INSTATE_BASISSTATES(:,:) = (0.0D0,0.0D0)
INSTATE_BASISSTATES(1,1) = ((1.0D0/SQRT(2)),0.0D0)
INSTATE_BASISSTATES(3,1) = ((1.0D0/SQRT(2)),0.0D0)
When I run/compile the program using gfortran on cygwin, I get the error
INSTATE_BASISSTATES(1,1) = (1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
1
Error: Expected a right parenthesis in expression at (1)
INSTATE_BASISSTATES(3,1) = (1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
1
Error: Expected a right parenthesis in expression at (1)
What could be the issue? Aren't my brackets correct?
On the right hand side of the assignment statement you are trying to use a complex literal constant. However,
(1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
isn't a valid form for such a constant.
For a complex literal, the real and imaginary components must be either named constants or literal constants. 1.0D0/DREAL(SQRT(2.0D0)) is neither of those things. For the line where you had no complaint, both components of (0.0D0,0.0D0) are literal constants.
As in this other answer you could make a named constant with the value wanted and use that. Alternatively, as you are just doing a boring assignment (which doesn't have various restrictions which apply to initialization, etc.,) you can use the cmplx intrinsic to return a complex value
INSTATE_BASISSTATES(1,1) = CMPLX(1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
Here the real and imaginary components don't need to be constants. You could even note that
INSTATE_BASISSTATES(1,1) = CMPLX(1.0D0/DREAL(SQRT(2.0D0)))
works just as well: if the imaginary component value isn't provided, the returned complex has imaginary component zero.
There is a slight complication, though. cmplx by default returns a complex number with kind of the default real. To return something matching complex*16 (which isn't standard Fortran, but let's assume it corresponds to double precision) you'll need CMPLX(..., [...], KIND=KIND(0d0)) (or KIND=KIND(INSTATE_BASISSTATES))
As a side note, as Vladimir F comments dreal isn't standard Fortran. You could use dble, or real with a suitable kind number. But we can also see that sqrt(2d0) already returns a double precision real, so even those are redundant: 1/sqrt(2d0) has the same (mathematical) result as the original more cumbersome expression. As do 2d0**(-0.5) and sqrt(2d0)/2.
You could even replace the right hand side with
SQRT((5d-1,0))
as we see that sqrt also accepts a complex argument (in this case a complex literal constant). This form also avoids the awkwardness of the kind= specifier: its value has kind as well as type of the argument.
this is indeed "by design", one could define the constant of interest first and then use it in the initialization. For example:
COMPLEX*16, DIMENSION(4,1) :: INSTATE_BASISSTATES
REAL*8, PARAMETER :: my_const = 1D0 / SQRT(2D0)
INSTATE_BASISSTATES(:,:) = (0.0D0,0.0D0)
INSTATE_BASISSTATES(1,1) = (my_const,0.0D0)
INSTATE_BASISSTATES(3,1) = (my_const,0.0D0)
However, the statement REAL*8, PARAMETER :: my_const = 1D0 / SQRT(2D0) seems to require at least Fortran2003 standard, otherwise, following error is produced Elemental function as initialization expression with non-integer/non-character arguments. One can specify the standard with gfortran with -std=f2003 although it should be probably active by default.
#J123 still hasn't answered the pressing question. Are you writing your code in fixed-form format with .f extension or free-form .f90? Also, what version of gfortran are you using? I've posted a complete fix below. You can foliate your arrays by direct assignment using named parameter constants, or as the return value of the intrinsic transformational function cmplx. Please note the liberal use of the kind parameter wp to control the floating-point precision.
program main
use iso_fortran_env, only: &
wp => REAL64, & ! Or REAL128 if your architecture supports it
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
complex(wp) :: instate_basisstates(4,1)
real (wp), parameter :: ZERO = 0 ! Assigning integers is safe
real (wp), parameter :: SQRT2 = sqrt(2.0_wp)
real (wp), parameter :: ONE_OVER_SQRT2 = 1.0_wp/SQRT2
! Executable statements
instate_basisstates(:,:) = ZERO
instate_basisstates(1,1) = (ONE_OVER_SQRT2, ZERO)
instate_basisstates(3,1) = cmplx(1.0_wp/sqrt(2.0_wp), 0.0_wp, kind=wp)
print '(/4a/)', &
'This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
This yields:
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -O3 -Wall -std=f2008ts

Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:
module test_mod
implicit none
integer, target :: a=1, b=2, c=3 ! some member variables
contains
function get(i)
integer, pointer :: get
integer, intent(in) :: i
select case (i)
case (1)
get => a
case (2)
get => b
case (3)
get => c
end select
end function get
end module test_mod
program test
use test_mod
implicit none
integer, pointer :: i_p
!> prints out 1 2 3
print*, get(1), get(2), get(3)
!> this is what I want but I get the error
!> Error: 'get' at (1) is not a variable
get(2) = 5
!> this works but is not what I want
i_p => get(2)
i_p = 5
end program test
Is there any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as
set(i,value)
since it should mimic the appearance of an array.
In my application, the member variables a,b,c are actually arrays of different size
a = [a1, a2, a3]
b = [b1, b2]
c = [c1]
and I want the getter get(i,j) to mimic a matrix of pointers
j = 1 2 3
i = 1: [[a1, a2, a3],
i = 2: [b1, b2, XX],
i = 3: [c1, XX, XX]]
wehre XX would be referencing to null().
Update:
I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?
Update 2:
So I ended up implementing a structure as follows
type Vec_t
integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data
which I initialise like this (my triangular matrix application I mention at the end)
allocate(data(max))
do i=1,max
allocate(data(i)%vec(i))
end do
and I access & write to it through
print*, data(2)%vec(1)
data(2)%vec(1) = 5
which is not precisely what I was after but good enough for my application.
Let's look at what you want to do:
get(2)=5
and the error message
Error: 'get' at (1) is not a variable
That looks pretty comprehensive: you can't do what you want. Or, perhaps...
get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.
The left-hand side of an assignment must be a variable.
But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which
shall have a data pointer result.
This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as
A pointer function reference can denote a variable in any variable definition context.
get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.
Alas, this interpretation of Fortran is not widely supported by current compilers: at the time of answering just the Cray compiler.
This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.
I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.

Initialization in Fortran Using Modules

I use the Intel Visual Fortran. The problem I'm dealing with has many PARAMETERS and I want to avoid repetitious declaration and initiation of them at the beginning of each routine.
Is there any way for initialization these PARAMETERS using MODULES?
Of course the answer is YES, but some of intrinsic function are not accepted in the initiation statement. Here is a simple sample code,
MODULE mod
IMPLICIT NONE
REAL, PARAMETER :: x = SQRT ( 4 )
END MODULE
PROGRAM prog
USE mod
IMPLICIT NONE
PRINT *, x
END PROGRAM
Once compiled, the compiler shows me this error :
Error #6362: The data types of the argument(s) are invalid.
[SQRT] Source1.f90
Albeit using ABS ( ) is not followed by this error, but SIN ( ) does.
The problem is that the sqrt (and sin) intrinsic requires a floating point argument. There just happens to be both floating point and integer implementations of abs.
Replace 4 with 4. and it should work.

Convert logical type to double in Fortran

I'm looking for a bulletproof way of converting logical type variables to real type that will work in both ifort and gfortran. The following works in ifort, but not in gfortran:
logical :: a
real :: b
a = .true.
b = dble(a)
The error thrown in gfortran is
b = dble(a)
1
Error: 'a' argument of 'dble' intrinsic at (1) must be a numeric type
Obviously, .true. should map to 1.d0, and .false. to 0.d0. What's the best way of doing this?
In addition to writing a function to handle this, you could also directly use the intrinsic merge function: b = merge(1.d0, 0.d0, a). Or you could write a defined assignment subroutine that does this, so that you can just type b = a.
I am not sure if there is an intrinsic tool that does this. I do not know why ifort accepts this, and my guess would be that it is a compiler specific functionality.
Edit: As pointed out in https://stackoverflow.com/a/15057846/1624033 below, there is the intrinsic merge function which is exactly what is needed here.
an option to to this, specifically since you want this to be bullet proof, is to create your own function.
I have not tested this, but the following might work:
elemental pure double precision function logic2dbl(a)
logical, intent(in) :: a
if (a) then
logic2dbl = 1.d0
else
logic2dbl = 0.d0
end if
end function logic2dbl
Edit: I added elemental to the function declaration based on advice below. I also added pure to this function as it adds the extra ability to use this in parallel situations and it is good documentation. This however is just my opinion and it is not necessary.
In gfortran, I am using the TRANSFER intrinsic for that type of job.
Assuming a integer variable my_int then:
my_int = transfer(.false.,my_int)
the result of my_int is 0 as expected.
Just a note, TRANSFER(.true.,1) correctly returns the value of 1 with Gfortran and (incorrectly?) values of -1 with the current versions of Intel and Portland compilers. Interestingly, TRANSFER(-1,logical) returns TRUE with the latter two compilers while throws a syntax error with Gfortran.