Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Fortran 90/95, assumed shape arrays, and interface blocks

Status
Not open for further replies.

billgray1234

Programmer
Mar 14, 2011
39
i'm a bit confused.

i'm using Fortran 90/95. i'm using modules; each module CONTAINS one (and only one) subroutine.

i want to use 'assumed shape arrays' in all of my subroutines. this means that, when declaring dummy argument arrays/matrices, i don't need to declare the dimensions of each array/matrix -- instead, the dimensions are 'assumed' to be the same as those of the actual argument.

so, for example, instead of having, say

MODULE SOME_MODULE
CONTAINS
SUBROUTINE SOME_SUBROUTINE(MATRIX,IMATRIX,JMATRIX)
REAL, DIMENSION(IMATRIX,JMATRIX), INTENT(IN) :: MATRIX
END SUBROUTINE SOME_SUBROUTINE
END MODULE SOME_MODULE


i can instead have


MODULE SOME_MODULE
CONTAINS
SUBROUTINE SOME_SUBROUTINE(MATRIX)
REAL, DIMENSION:),:), INTENT(IN) :: MATRIX
END SUBROUTINE SOME_SUBROUTINE
END MODULE SOME_MODULE


most books that i've read (and also the internet) say that, in order to use 'assumed shape arrays', you MUST provide an interface block. for example


INTERFACE
SUBROUTINE SOME_SUBROUTINE(MATRIX)
REAL, DIMENSION:),:), INTENT(IN) :: MATRIX
END SUBROUTINE SOME_SUBROUTINE
END INTERFACE


however, one source that i've read said that an interface block is not necessary -- IF (and only IF) the subroutine is 'contained' within a module (i.e. using the word CONTAINS) -- like in the above example. otherwise, an interface block IS necessary (i think, for example, like in Fortran 77).


so, my questions are:-

1) is it ALWAYS necessary to use an interface block? or, as the above source said, is it permissible to NOT use one -- IF (and only IF) the subroutine is 'contained' within a module (i.e. using the word CONTAINS)?

2) if it is permissible to NOT use an interface block (i.e. using the word CONTAINS in a module), is it STILL OK to use one, anyway? for example, for added security in programming, and good 'book-keeping'.
 
I feel like you are asking the wrong questions...humor me and forget about the interface for now.

Instead, let's focus on declaring the matrix properly...My understanding about 'assumed' shape arrays is that they need the size of all dimensions but the last one. In other words, the declaration should be something like this:

REAL, DIMENSION(IMATRIX,*), INTENT(IN) :: MATRIX

So, give that a try, just to see if you get a working program and THEN you may try to proceed an attempt to do away even with that parameter.
 
thanks for that reply.

i'll go back a step, and explain the situation further, so you can see where my confusion arises.


again, i'm using Fortran 90/95 (not Fortran 77). to my understanding, when it comes to sending arrays as arguments (to subroutines etc), there are 2 distinct concepts:-

1) 'assumed SIZE arrays' (a feature of Fortran 77)
2) 'assumed SHAPE arrays' (a feature of Fortran 90)

with emphasis on the words SIZE and SHAPE (rather than the word 'assumed').
with assumed SIZE arrays, you explicitly declare all but the last dimension of the array -- the last dimension is declared simply as (*), just like you said in your reply.
on the other hand, with assumed SHAPE arrays, you don't explicitly declare any of the array dimensions -- each dimension is declared simply as :)), just like in my example above.

for example, although i don't know how accurate it is (but i think it IS fairly accurate), check out the article at
( it mentions both 'assumed SIZE arrays' and 'assumed SHAPE arrays'. it also mentions interface blocks, and the 'USE module' command.

but, the article still adds to my confusion about whether interface blocks are needed, or whether just having the 'USE module / CONTAINS' features is sufficient enough. for example, it says:

The extra information that is needed is generated by the
"use module" command, OR by an "interface command".

in other words, one OR the other. but, is having BOTH also ok? also, is having BOTH essential?

also, in regard to 'book-keeping', the article says:

But SOMETIMES interface blocks are used to give the compiler
EXTRA argument-checking abilities at compile time.

does that mean to say that, if my program works fine with JUST the 'USE module' command, that it IS ok (but not strictly essential) to ALSO have an interface block (for extra programming security)? note that this question is mainly for curiousity -- because i have a LOT of subroutines, and so i'd much rather just use the 'USE module' command than (also) have many interface blocks.

in summary, you seem to have described assumed SIZE arrays (as opposed to assumed SHAPE arrays). i'm interested in assumed SHAPE arrays. but, as you suggested, i HAD been writing a small 'test' program, in order to experiment with this topic.

again, thanks for your reply. sorry if i've confused things even further!
 
Oh, I see...my mistake...I don't have much experience with Fortran 90 and, hence, totally thought we were talking about assumed size arrays, the kind Fortran 77 can handle.

I have started to use Fortran 90, but it is Friday night and my Fortran 90 book is at the office.

But I already read my book and while it is not here to consult it, now that you mention it, I do remember reading about modules and interfaces and assumed shape arrays.

If I remember correctly, if your interfaces are all very different, you do not need to declare interfaces...the simple fact that you have included your subroutine inside the module will cause the compiler to automatically generate an interface for you. No worries there.

Of course, now you are going to ask...o.k., then, so, when do I need interfaces?

There are a few instances when they are convenient and/or necessary...but I guess we don't have to talk about that right now. :)

 
It works when you declare it in module with CONTAINS:
Code:
module your_module
  ...
contains    
  function your_function(your_array, ...)
  ...
  end function your_function
end module your_module

program your_program
    use your_module
...
end program your_program
or directly in your program using CONTAINS
Code:
program your_program
  ...
contains    
  function your_function(your_array, ...)
  ...
  end function your_function
end program your_program
Try the working example with FUNCTION MatrixVector(M, x) I posted here:
 
To your question with the INTERFACE:
Normaly when we want to use the function which is defined neither in module nor in the main program using CONTAINS, we have to declare the function as EXTERNAL in main program - e.g.:
Code:
program my_prog
  ! declare the external function
  real, external :: my_foo
  ...
  ! call the function
  res = my_foo(...)
  ...
end program my_prog

! define function
real function my_foo(...)
  ...
end function my_foo
But with the above function MatrixVector(M, x) this doesn't work. Here helps to use in the main program the INTERFACE:
Code:
[COLOR=#a020f0]program[/color] main
    [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
    [COLOR=#a020f0]interface[/color]
      [COLOR=#a020f0]function[/color] MatrixVector(M, x)
        [COLOR=#0000ff]! Matrix-Vector multiplication /for square Matrices only/[/color]
[COLOR=#2e8b57][b]        real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](:,:), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: M
[COLOR=#2e8b57][b]        real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](:), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
        [COLOR=#2e8b57][b]integer[/b][/color] ::n, i, j
[COLOR=#2e8b57][b]        real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](n) :: MatrixVector
      [COLOR=#a020f0]end function[/color]
    [COLOR=#a020f0]end interface[/color]
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color])   :: v, w
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color],[COLOR=#ff00ff]2[/color]) :: A
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]3[/color])   :: u, t 
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]3[/color],[COLOR=#ff00ff]3[/color]) :: B
    [COLOR=#2e8b57][b]integer[/b][/color] :: j

    [COLOR=#0000ff]!****************************************************************[/color]
    [COLOR=#0000ff]!*** Example 1: [/color]
    [COLOR=#0000ff]!****************************************************************[/color]
    [COLOR=#0000ff]! construct Vector[/color]
    v[COLOR=#804040][b]=[/b][/color]([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]1[/color]., [COLOR=#ff00ff]2[/color].[COLOR=#804040][b]/[/b][/color])
    [COLOR=#0000ff]!print *, v ! print Vector[/color]
    [COLOR=#0000ff]! construct Matrix by columns and reshape[/color]
    A [COLOR=#804040][b]=[/b][/color] [COLOR=#008080]reshape[/color](([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]1[/color].,[COLOR=#ff00ff]3[/color].,[COLOR=#ff00ff]2[/color].,[COLOR=#ff00ff]4[/color].[COLOR=#804040][b]/[/b][/color]), ([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]2[/color], [COLOR=#ff00ff]2[/color][COLOR=#804040][b]/[/b][/color])) 
    [COLOR=#0000ff]!print *, A ! print Matrix by columns[/color]
    w [COLOR=#804040][b]=[/b][/color] MatrixVector(A, v)
    [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]"u = "[/color], (w(j), j [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]1[/color], [COLOR=#ff00ff]2[/color])

    [COLOR=#0000ff]!****************************************************************[/color]
    [COLOR=#0000ff]!*** Example 2: [/color]
    [COLOR=#0000ff]!****************************************************************[/color]
    [COLOR=#0000ff]! construct Vector[/color]
    u [COLOR=#804040][b]=[/b][/color]([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]1[/color]., [COLOR=#ff00ff]1[/color]., [COLOR=#ff00ff]1[/color].[COLOR=#804040][b]/[/b][/color])
    [COLOR=#0000ff]!print *, u ! print Vector[/color]
    [COLOR=#0000ff]! construct Matrix by columns and reshape[/color]
    B [COLOR=#804040][b]=[/b][/color] [COLOR=#008080]reshape[/color](([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]1[/color].,[COLOR=#ff00ff]2[/color].,[COLOR=#ff00ff]3[/color].,[COLOR=#ff00ff]1[/color].,[COLOR=#ff00ff]2[/color].,[COLOR=#ff00ff]3[/color].,[COLOR=#ff00ff]1[/color].,[COLOR=#ff00ff]2[/color].,[COLOR=#ff00ff]3[/color].[COLOR=#804040][b]/[/b][/color]), ([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]3[/color], [COLOR=#ff00ff]3[/color][COLOR=#804040][b]/[/b][/color]))
    [COLOR=#0000ff]!print *, B ! print Matrix by columns[/color]
    t [COLOR=#804040][b]=[/b][/color] MatrixVector(B, u)
    [COLOR=#804040][b]print[/b][/color] [COLOR=#804040][b]*[/b][/color], [COLOR=#ff00ff]"t = "[/color], (t(j), j [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]1[/color], [COLOR=#ff00ff]3[/color])
[COLOR=#a020f0]end program[/color] main

[COLOR=#a020f0]function[/color] MatrixVector(M, x)
  [COLOR=#0000ff]! Matrix-Vector multiplication /for square Matrices only/[/color]
[COLOR=#2e8b57][b]  real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](:,:), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: M
[COLOR=#2e8b57][b]  real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](:), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
  [COLOR=#2e8b57][b]integer[/b][/color] ::n, i, j
[COLOR=#2e8b57][b]  real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color](n) :: MatrixVector
  n[COLOR=#804040][b]=[/b][/color][COLOR=#008080]SIZE[/color](x)
  [COLOR=#0000ff]!print *, n[/color]
  [COLOR=#804040][b]do[/b][/color] i[COLOR=#804040][b]=[/b][/color][COLOR=#ff00ff]1[/color], n
    MatrixVector(i)[COLOR=#804040][b]=[/b][/color][COLOR=#ff00ff]0[/color].
    [COLOR=#804040][b]do[/b][/color] j[COLOR=#804040][b]=[/b][/color][COLOR=#ff00ff]1[/color], n
      MatrixVector(i) [COLOR=#804040][b]=[/b][/color] MatrixVector(i) [COLOR=#804040][b]+[/b][/color] M(i,j)[COLOR=#804040][b]*[/b][/color]x(j)
    [COLOR=#804040][b]enddo[/b][/color]
  [COLOR=#804040][b]enddo[/b][/color]
[COLOR=#a020f0]end function[/color] MatrixVector
Code:
$ gfortran vector_external.f90 -o vector_external

$ vector_external
 u =    5.0000000       11.000000    
 t =    3.0000000       6.0000000       9.0000000
 
first, sorry about the delay in THIS reply -- i've been out of town for the past week.

thanks for all the replies!

based on your replies, i've summarised everything below. can someone please confirm whether it is all correct? thanks. note that, in the summary, i've made reference to using subroutines only; however, the same 'rules' should also apply when functions are used instead.

SUMMARY
in Fortran 90/95, when 'assumed SHAPE arrays' are used (in subroutines), an explicit interface block MUST be used.
however:-

1) if the subroutine is 'contained' inside a module (using the word CONTAINS), and is 'used' by either the main program or another subroutine (using the word USE module_name), then we DO NOT have to create the interface block ourselves -- instead, the compiler does that for us automatically (just like salgerman suggested)

2) otherwise, we DO have to create the interface block ourselves (just like mikrom suggested)
 
also, check out some of the replies (particularly the one by IanH) in the thread

'Need generic subroutine with array or simple argument'

at the intel visual fortran website


that thread mentions interface blocks and modules, and further supports the replies you all gave above.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top