Why "There is no specific subroutine for the generic ‘la_syevd’"? - module

I'm using Lapack95 to calculate some eigenvalue problem. I managed to successfully call the necessary subroutine from the main program. However, when I try to call it from a module, it issues the error:
There is no specific subroutine for the generic ‘la_syevd’'
Clearly this suggests that I did not load the proper module from inside the new module I'm developing, but it is not the case. Do you have an idea of what's going on here? This has to be a silly mistake somewhere, but I can not see it.
More concretely, the minimal example that reproduces the issue is shown below.
module EOF
use F95_LAPACK, only: LA_SYEVD !! this does not seem to load the interface here, but it does in the main program ?!
implicit none
contains
subroutine diagonalise(a, eigenvectors, eigenvalues)
real, dimension(:,:), intent(in) :: a
real, dimension(size(a,2),size(a,2)), intent(out) :: eigenvectors
real, dimension(size(a,2)), intent(out) :: eigenvalues
integer :: info
call la_syevd(a=a, w=eigenvectors, jobz='V', info=info) !!! THIS CALL DOES NOT WORK
end subroutine
end module EOF
program mkeof
use F95_LAPACK, only: LA_SYEVD
use EOF
implicit none
integer :: i, j, info
real, allocatable :: a(:,:), w(:)
allocate(a(5,5), w(5))
call random_number(a)
call la_syevd(a=a, w=w, jobz='V', info=info) !!! THIS CALL WORKS
print*, 'END'
end program mkeof

Related

Is "intent" guaranteed for contained subroutines inside a module contained subroutine?

I am wondering if the following code is legal:
module my_mod
contains
subroutine my_outer_sub(a)
integer, intent(in) :: a
call my_inner_sub()
contains
subroutine my_inner_sub()
a=3 ! this compiles and runs!
end subroutine my_inner_sub
end subroutine my_outer_sub
end module my_mod
I compiled the code with PGI 17.4. I have been using contained subroutines inside module subroutines and now I wonder if this scheme is a suitable one?
No, the code is illegal. You cannot modify an intent(in) argument. This is an error in the compiler and should be reported to your vendor.
Gfortran identifies it correctly
Error: Dummy argument 'a' with INTENT(IN) in variable definition context (assignment) at (1)
and so does Intel Fortran
intent3.f90(11): error #6780: A dummy argument with the INTENT(IN) attribute shall not be defined nor become undefined. [A]
a=3 ! this compiles and runs!
------^
compilation aborted for intent3.f90 (code 1)

Structure of a fortran program with modules and subroutines

This is part of a main program
PROGRAM program1
USE method
USE variables
IMPLICIT NONE
:
CALL method_init(A,a1end,C)
:
END PROGRAM program1
The call to method_init, contained in the module method, "initializes" a method in that it builds arrays a1end and C form the array A (other calls to other procedures contained in the module should follow).
Arrays a1end and C are part of the method, so they are both declared in the method module; the array A is not part of the method (it could be "solved" with another method), so it is declared in the module variables.
The arrays C and a1end could be used by subroutines not contained in the method module, so they must be declared before the CONTAINS statement.
So, the subroutine contained in the method module could use these variables without using them as input/output variables, but this would make unclear the role of the subroutine (the call would be simply CALL method_init, so "How does this subroutine operate? Which arrays does it use? And which modify? ..."), so I prefer to have the call as CALL method_init(A,a1end,C).
This means that the module method is like this
MODULE method
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE :: C ! declared here to be used...
REAL, DIMENSION(:,:), ALLOCATABLE :: a1end ! ...by procedures outside this module
:
CONTAINS
SUBROUTINE method_init(A,a1end,C)
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A ! deferred shape (it's allocated elsewhere in the main program)j
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: C ! declared here to be used...
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: a1end ! ...as input/output variables
:
ALLOCATE(C( ),a1end( ))
:
END SUBROUTINE method_init
END MODULE method
I'd like to know if this is a correct way of programming. Is it just a matter of taste?
EDIT The question, in short, is:
Is a correct way of programming to use variables defined in a module as input/output arguments of procedure contained in the module itself? Or it is better to write subroutines with no arguments? Or everything is just a matter of taste?
The questions/answers linked by #Vladimir F make me think that yes, it' a matter of taste. Nevertheless none of these question touches the specific point I'm interested into (i.e. procedures that are in a module and use a variable defined in the module as input/output arguments).
My answer would be that you did the right choice as I would always recommend to write procedures with all its parameters and avoid using global variables (like C and a1end in your example).
However, many people in Fortran use to use global variables and would not bother passing these arguments, sometimes for wrong reason (like "it's faster to write").
But it is still totally correct to use global variable in a module if you imagine the latter as being a box containing its own specific and unique set of parameters. Maybe then you would want to specify them as Fortran parameter (with the associated keyword).
When you question yourself about passing arguments or using global variables for a function/subroutine, a simple choice would be whether or not your function is bound to be called/reused with other different parameters somewhere else in your code, or sometime later in your development process.
This is particularly true when you think of your module as a box that you can unplug and give to a mate for his own needs, then you might want your method_init to be more flexible, thus expliciting the arguments.
Note: in your example, I would recommend to name your subroutine arguments differently than your module's variables in order to avoid any confusion in the code and be able to use them without any conflict:
MODULE method
IMPLICIT NONE
REAL, DIMENSION(:,:), ALLOCATABLE :: C
REAL, DIMENSION(:,:), ALLOCATABLE :: a1end
CONTAINS
SUBROUTINE method_init(A,my_a1end,my_C)
IMPLICIT NONE ! Already specified above
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_C
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_a1end
ALLOCATE(my_C( ),my_a1end( ))
! Here you can work with module's C and a1end
! Given that they have been effectively allocated
! You can also test whether C and my_C are the same object or not (pointerwise speaking)
END SUBROUTINE method_init
END MODULE method

Fortran tips in large modules

I have a module that consists of many small subroutines and one main subroutine, which is the only one that is public. The rest of the subroutines are private and called by the main subroutine or within them. The main subroutine has to take all the necessary arguments to perform its work, but often when it delivers a task to a private subroutine, it has to pass again some of the arguments. I would like to avoid this when dealing with arrays. With scalar numbers I can simply define a module wide variable and assign it the corresponding value in the main subroutine:
module test
integer, private :: m, n
private :: foo
public :: main
contains
subroutine main(matrixA, m0, n0)
integer, intent(in) :: m0, n0
real, intent(inout) :: matrixA(m0,n0)
!assign values to module variables m & n
m = m0
n = n0
...
!no need to pass m0 & n0
call foo(matrixA)
end subroutine
subroutine foo(matrixA)
real, intent(inout) :: matrixA(m,n)
...
end subroutine
end module
I would like to also not need to pass matrixA at all. What is the best way to do this? By best, I mean giving the best performance.
I can't comment on the "best" way, but there are some things to say. And now the question has been edited to point "best" in the direction of performance I'll add something else.
The question appears to be made under the premise that arrays cannot be module variables. They can be, even allocatable/pointer (deferred-shape) ones.
In the examples that follow I'll make the assumption that the array dummy argument in main will be assumed-shape. This is just to make things simpler in the form; changing to explicit-shape is a simple extension.
First, just like we set m and n in the question, we can set a module array variable.
module test
private ! Have this as default
public main ! But we do want a way in
integer m, n
real, allocatable :: matrixA(:,:)
contains
! In this subroutine we're making an assumption that the person asking isn't
! wholly correct in not wanting to assume shape. But we can change that if
! required. It's just a more natural thing if one can.
subroutine main(matrix) ! Note, not passing m, n
real, intent(inout) :: matrix(:,:) ! It's assumed shape
m = SIZE(matrix,1)
n = SIZE(matrix,2)
matrixA = matrix ! Copy in to the module's matrixA
call foo()
! .... etc.
matrix = matrixA ! Copy back out to the dummy
end subroutine main
subroutine foo
! Here we have access to the module's matrixA
! And we do our stuff
end subroutine foo
end module test
Note the use of the assumed-shape dummy argument and the discussion above. To avoid copying in this example, one could think about whether using a pointer is a suitable thing.
With the copy, that's not going to be good performance (assuming the array is biiig). So:
module test
implicit none
private
integer m, n ! If we want these we'll have to set them somehow
real, allocatable, public :: matrixA(:,:)
public main
contains
subroutine main()
! Stuff with matrixA host-associated
end subroutine main
end module test
program hello
use test, only : matrixA, main
implicit none
matrixA = ... ! Set this: it's matrixA from the module
call main
end program hello
As we care about "performance" rather than "encapsulation" that seems like a reasonable thing. However, having encapsulation, performance and reduced-argument passing, we could consider, rather than using a module variable for matrixA, having the work subroutines internal to main.
module test
contains
subroutine main(matrixA)
real, intent(inout) :: matrixA(:,:)
call foo
contains
subroutine foo
! Here we have access to matrixA under host association
end subroutine foo
end subroutine main
end module test
In many circumstances I prefer this last, but wouldn't say it's best, or even preferred under all circumstances. Note, in particular, that if foo already has an internal subprogram we'll start to wonder about life.
I feel the first is rather extreme just to avoid passing as an argument.

fortran 2003 seg fault with overridden type-bound procedure

I'm trying to use some of the object-oriented features of Fortran 2003 and I'm running into some trouble. First off, I have an abstract data type sparse_matrix:
type, abstract :: sparse_matrix
(some data)
contains
procedure(matrix_vector_multiply), deferred :: matvec
end type sparse_matrix
abstract interface
subroutine matrix_vector_multiply(A,x,y)
import :: sparse_matrix
class (sparse_matrix), intent(in) :: A
real(kind=8), dimension(:) :: x,y
end subroutine matrix_vector_multiply
end abstract interface
then I have a concrete data type which inherits from sparse_matrix
type, extends(sparse_matrix) :: csr_sparse_matrix
(some more data)
contains
procedure :: matvec => csr_matvec
end type csr_sparse_matrix
and the actual implementation of matvec:
subroutine csr_matvec(A,x,y)
class (csr_sparse_matrix), intent(in) :: A
real(kind=8), dimension(:) :: x,y
(do stuff)
end subroutine csr_matvec
Later, I want to use matvec in a different module, and I don't care which dynamic type I've got:
subroutine solve(A,x,b,tolerance)
class (sparse_matrix), intent(in) :: A
real(kind=8), dimension(:), intent(in) :: b
real(kind=8), dimension(:), intent(out) :: x
real(kind=8), intent(in) :: tolerance
real(kind=8), dimension( A%nrow ) :: z
call A%matvec(b,z)
(more stuff)
end subroutine solver
My understanding is that everything should work fine, no matter what dynamic type A is, so long as the subroutine matvec has been overridden in the child data type.
This code compiles just fine, but it seg faults when I run it. When I change the declaration of the matrix in the solve procedure as follows:
class (csr_sparse_matrix), intent(in) :: A
it works just fine. Likewise, if I leave A as a sparse_matrix but use
select type(A)
type is (csr_sparse_matrix)
(the same stuff)
end select
then everything runs fine too. But this defeats the whole purpose of overriding the procedures of an abstract type in the first place -- the program shouldn't care what kind of matrix I'm using, as long as it can perform a matrix-vector multiplication.
Anyhow, I'm sure it's just a matter of some attribute that I forgot to include, but I can't figure out what it is.
So it was the compiler after all; I was using gfortran 4.6.3, whereas abstract data types were only properly supported as of gfortran 4.7. Unfortunately, this makes my code not so portable, as the long-term support releases of several linux distributions only include version 4.6.

File IO using polymorphic datatypes in Fortran

I am writing a library for importing geometries of many types (spheres,planes,NURBS surfaces, stl files...) into a scientific Fortran code. This kind of problem seems taylor-made for OOP because it is simple to define a type :: geom and then type,extends(geom) :: analytic and so on. The part I am having trouble with is the file IO.
My solution at this point is to write the parameters defining the shapes, including some flags which tell me which shape it is. When reading, I instantiate a class(geom) :: object, (since I don't know ahead of time which subtype it will be) but how can I read it?
I can't access any of the specific components of the subtype. I read that downcasting is verboten, and besides, the new allocate(subtype :: class) doesn't seem to work. The new READ(FORMATTED) doesn't seem to be implemented by ifort or gfortran. i.e.
module geom_mod
type :: geom
end type
type,extends(geom) :: sphere
integer :: type
real(8) :: center(3),radius
contains
generic :: READ(FORMATTED)=> read_sphere ! not implemented anywhere
end type
contains
subroutine read_geom(object)
class(geom),intent(out),pointer :: object
integer :: type
read(10,*) object%type ! can't access the subtype data yet
read(10,*) type
backspace(10)
if(type==1) then
allocate(sphere :: object)! downcast?
read(10,*) object ! doesn't work
end if
end read_geom
end module
Am I going about this all wrong? I could hack this using something other than polymorphism, but this seems cleaner everywhere else. Assistance would be greatly appreciated.
EDIT: sample program using IanH's module
program test
use geom_mod
implicit none
class(geom),allocatable :: object
open(10)
write(10,*) '1'
write(10,*) sphere(center=0,radius=1)
rewind(10)
call read(object) ! works !
end program test
Current gfortran and ifort do not implement defined input/output. I have not seen any evidence that this situation will change in the near future. However, apart from allowing some syntactic shortcuts that feature does not actually save you much work here.
One approach for this situation is to call a "factory" for extensions of geom that uses the data in the file to allocate the argument to the correct type, then hand off to a type bound procedure that reads in the type specific data. For example:
module geom_mod
implicit none
integer, parameter :: dp = kind(1.0d0)
type, abstract :: geom
contains
procedure(read_geom), deferred :: read
end type geom
abstract interface
subroutine read_geom(object)
import :: geom
implicit none
class(geom), intent(out) :: object
end subroutine read_geom
end interface
type, extends(geom) :: sphere
real(dp) :: center(3), radius
contains
procedure :: read => read_sphere
end type sphere
contains
subroutine read(object)
class(geom), intent(out), allocatable :: object
integer :: type
read (10, *) type
! Create (and set the dynamic type of object) based on type.
select case (type)
case (1) ; allocate(sphere :: object)
case default ; stop 'Unsupported type index'
end select
call object%read
end subroutine read
subroutine read_sphere(object)
class(sphere), intent(out) :: object
read (10, *) object%center, object%radius
end subroutine read_sphere
end module geom_mod
Current ifort (12.1.5) has issues with intent(out) polymorphic arguments that may require workarounds, but the general approach remains the same.
(Note that the subroutine read is not a type bound subroutine - to read a generic geom object use ''call read(object)'' in the conventional subroutine reference style.)