Can a Fortran 90 assumed shape array be an OPTIONAL argument? - fortran

NOTE: I'm still investigating this issue - please don't look into it yet - the mistake may be elsewhere
I would like an argument to a subroutine to be OPTIONAL, but that argument also happens to be an assume shape array. When I try to compile the module containing this subroutine, I get the following error:
PGF90-S-0189-Argument number 3 to (routine): association of scalar actual argument to array dummy argument (location)
The routine looks like this:
SUBROUTINE EXAMPLE(A, B, C)
IMPLICIT NONE
INTEGER, INTENT(IN) :: A, B
INTEGER, OPTIONAL, DIMENSION(:), INTENT(IN) :: C
INTEGER :: TEST
IF (PRESENT(C)) THEN
TEST=C(1)
PRINT *,TEST
ELSE
PRINT *,A,B
ENDIF
END SUBROUTINE EXAMPLE
It is contained within a module. I get the error when I try to call it with only two arguments from a subroutine which is USEing the module.
I have only found one possibly related question on the Portland Group forums here:
http://www.pgroup.com/userforum/viewtopic.php?t=624&sid=d76fdf8ca2bf4fc3109f4f49b1de0ad7
The answer boils down to the user using an optional argument which has not been allocated - I don't know if this applies in my case as I'm not using 'C' outside of the IF(PRESENT(C)) block, but could there be an implicit allocation going on when defining a variable as assumed shape, which cannot be carried out when it is not passed in the first place?

This problem is now resolved - you can indeed use assumed shape arrays as optional arguments. As pointed out in the comments - the error stemmed from an old version of a source file which was not being regenerated by a pre-processing step due to a bug. As a result, the call was not what I thought it was - it actually contained a single integer as the third argument.
Thanks for the help all.

Related

How to look up an object by name in Fortran [duplicate]

I want to create a dynamic variable name using Fortran.
The variable name will be obtained by concatenating a string and another string/integer. Then I want to use this variable name to store a value or another variable.
e.g.
! assign values to 2 variables
my_string = h
my_integer = 1
! perform concatenation resulting in the dynamic variable name, h1
! Set the value of variable h1 to another integer value
h1 = 5
I fear that you will not be able to do this. Fortran requires that variables have names and types at compile time. You (or other SOers) may come up with some kludge to simulate what you want, but it will be a kludge.
Why do you want to do this in Fortran ? There are plenty of languages around which do permit this sort of variable declaration.
EDIT
Well, I thought about it some more, and here's a kludge, unfinished. First a UDT for 'dynamic' variables:
type dynamic_var
character(len=:), allocatable :: label
class(*), allocatable :: value
end type
declare some space for such variables:
type(dynamic_var), dimension(:), allocatable :: run_time_vars
and, working with your original data
allocate(run_time_vars(10)) ! No error checking, reallocate if necessary
! lots of code
write(run_time_vars(1)%label,'(a1,i1)') my_string, my_integer
allocate(run_time_vars(1)%value, source = my_value)
This compiles, but doesn't run and I'm not going to stay long enough to fix it, I'll leave that as an exercise to anyone who cares.
The write to the label field isn't right.
The sourced allocation to the value field doesn't seem to work correctly. Might need to write a 'decode' function to use like this:
allocate(run_time_vars(1)%value, source = decode(my_value))
Like I said, it's a kludge.
I think you want to use a data structure. If you have pairs or groups of values that go together, then create a derived data type which can hold both. There's an explanation on this page:
http://web.mse.uiuc.edu/courses/mse485/comp_info/derived.html
If you have a list of these pairs (like your string and int above), then you can create an array of these types. Example code below taken from the page linked above:
type mytype
integer:: i
real*8 :: a(3)
end type mytype
type (mytype) var
Array:
type (mytype) stuff(3)
var%i = 3
var%a(1) = 4.0d0
stuff(1)%a(2) = 8.0d0
An significant benefit of doing this is that you can pass the pairs/groups of items to functions/subroutines together. This is an important programming principle called Encapsulation, and is used extensively in the Object Oriented programming paradigm.
No, this is not possible in Fortran.
For more information, look into Reflection (computer programming).
Clearly, for reasons given above, this is not legit Fortran (and thus you're going into trouble ...). You may use smart (congrats guys!) kludges, but ...
Instead of using variables h concatenated with 1, 2 or whatever number, why not creating array h(1:N) where N does not have to be known at compilation time : you just have to declare array h as a allocatable.
This is, I think, the legit way in Fortran 90+.

Fortran subroutine: How to load data only on first call

I am programming a Fortran module, which is linked to external main program. I can only alter the subroutine. I have to detail a lot of data, but always the same. It takes too much time to do this on every call of the subroutine. How can I initialise the data only at the first call?
Currently, this is the subroutine:
subroutine sdvini(statev,coords,nstatv,ncrds,noel,npt,layer,kspt)
implicit none
integer imdat(100,100,50)
imdat(1,1,1:33)=(/1,8,13,24,48,72,111,148,156,165,182&
&,189,194,207,210,216,236,247,254,270,311,319,339,343,367,376&
&,393,397,421,438,447,473,492/)
.
. lots of data
.
do something
return
end
This setting of values on the first call to a procedure and retaining the values can be performed by explicit initialization. We often use the term initialization, as in this question, to mean an assignment as part of a setting up process. However, initialization means something more precise in Fortran terms.
An explicit initialization suitable for this question would be something like the very simple case
integer, save :: i=1 ! SAVE attribute would be implied, but made explicit
This is like having the assignment applied the first time the procedure is entered.
We can also use a data statement:
integer, save :: i
data i /1/
The SAVE attribute is what ensures that the value persists between entries to the procedure.
For arrays the idea is the same, perhaps using array constructors and reshape.
For very large arrays it is impractical to use data statements or initializers. Further, there are restrictions on what may appear in initializing a saved local variable. However, another idiom would be like
subroutine sub
logical, save :: firsttime=.TRUE.
integer, save :: obj(100,100,50)
if (firsttime) then
obj = ... ! Setting the value somehow, maybe even with a read
firsttime = .FALSE.
end if
end subroutine

Get size of array in uninstantiated user-defined data type

Say the following module is given to me, and I am not allowed to edit it:
module somemod
type somestruct
character(40) somestr
end type
end module
And I use it in this code:
program myprog
use somemod
implicit none
character(size(somestruct%somestr)) localstr !Is this possible?
end program
Is there syntax accomplish what the marked line is trying to do? That is, can I get the size of an array in an user-defined data structure without instantiating the data structure?
First,
character(40) somestr
is not an array, it is a character string of length 40.
The difference is substantial, it is not just nitpicking. You use arrays and strings differently. See Difference between "character*10 :: a" and "character :: a(10)" for more.
The length of a string is inquired by the intrinsic function len().
But unfortunately, you cannot call it on a component of a derived type, without first having a variable (instance) of that type.
So you need
program myprog
use somemod
implicit none
type(somestruct) :: o
character(len(o%somestr)) localstr !This is possible.
end program
If you needed the size of an array component, it would be the same, but with the size() intrinsic function.

Issue using common blocks in Fortran

I'm working with fortran subroutines of a finite element analysis program. I have to share variables between the two subroutines so I'm using COMMON blocks (EDIT: module is better). The problem is that only some of the variables are passed to the other subroutine, others are not.
My code is like this:
First subroutine:
real knom, krot
COMMON /kVAR/ kmom, krot
SAVE /kVAR/
Second subroutine I use the same syntax. I'm controlling the results by writing kmom and krot values in each subroutine to a txt file:
write(6,*) 'I am in URDFIL', or 'I am in UFIELD'
1 KINC, kmom, krot
The results are:
I am in URDFIL 1 -16700 -2.3857285E-03
I am in UFIELD 2 -16700 -1155769886
So the value of krot is lost. Any advise is most welcome.
João
Solved:
module shared_var
implicit none
real*8 kmom, krot
save
end module shared_var
And in each subroutine:
use shared_var
Did you include the declaration of knom, krot in the second routine? Probably you are getting implicit typing and krot is being output as an integer. And it appears that you have a typo: knom versus kmom. That is why kmom is output as an integer in both cases -- implicit typing as an integer since knom is the real. If implicit typing is in effect these variables will be integers since they begin with "k". My strong recommendation is to not use implicit typing unless it is too much work to remove from legacy code. It is highly recommended to use "implicit none" so that the compiler will warn you if you forget to type a variable or make a typo in a variable name. Most compilers have options that are equivalent to "implicit none".

Fortran 90 Presence Of Optional Arguments

I do not understand the behavior of the present() intrinsic function with pgf90 7.2. I wrote a 20 line sample program to test this, but the results still make no sense to me. Observe:
subroutine testopt(one,two,three,four,five)
implicit none
integer, intent(in) :: one,two
integer, intent(out) :: three
integer, intent(in), optional :: four
integer, intent(out), optional :: five
three = one + two
print *,"present check: ",present(four),present(five)
if (present(four) .and. present(five)) then
five = four*four
end if
end subroutine testopt
if I: call testopt(1,2,(any variable)) from my main program, it prints: "present check: T F". However if I: call testopt(1,2,(any variable)) from a subprogram it prints: "present check: T T". I expected to see "present check: F F" in either case, because I am only calling the subroutine with the 3 non-optional arguments, and neither of the optional ones. I cannot fathom why it would behave this way, and this is causing a major bug in a program I am working on. I appreciate any insight. Thanks.
Are you placing this subroutine in a module and then having a "use" statement for that module in the calling routine (main program or subroutine)? A typical rule is that many of the advanced / new features of Fortran 90 require an explicit interface so that both the caller and callee pass the arguments consistently. The easiest and best way to accomplish this is with module / use. Just a guess...
In Modern Fortran optional arguments must be declared as optional in the calling function (either through a module or an explicit interface). In Fortran 77 it was possible to simply leave out the last argument, if it was a scalar number, so optional arguments could be passed without extra declaration in the calling routine. This might not have been part of the Fortran standard, but it was a helpful feature provided by wise compiler implementations. Unfortunately, Modern Fortran killed this awesome feature.