Statement labels in wrapper functions - fortran

In Fortran, is there a way to pass a statement label through a wrapper function?
To elaborate, I am writing a wrapper for open(), like so:
program test
contains
subroutine my_open(unit, file, err)
integer, intent(in) :: unit
character(*), intent(in) :: file
integer, intent(in), optional :: err
if (present(err)) then
open(unit, FILE=file, ERR=err)
else
open(unit, FILE=file)
end if
end subroutine my_open
end program test
(of course my actual procedure contains more logic …). But gfortran complains
open(unit, FILE=file, ERR=err)
1
Error: Invalid value for ERR specification at (1)
Is there a way to do this?

The label corresponding to err has to be a label in the scoping unit of the open. So what you want to do isn't possible. Also, to answer your more general question, passing labels as variable isn't possible in itself (at least, since Fortran 95 which deleted assigned formats and gotos).
However, for the specific case, using iostat instead, and passing control back to the calling subprogram is possible.
Something like (simplified):
call my_open(12, file, status)
! Instead of:
! 10 STOP
if (status.ne.0) then
!...
end if
end
subroutine my_open(unit, file, status)
integer, intent(in) :: unit
character(*), intent(in) ::file
integer, intent(out) :: status
open(unit, file=file, iostat=status)
if (iostat.ne.0) return
end subroutine
This is arguably much better than having what would essentially be a goto to a very different part of the code from the subroutine. [err isn't popular at the best of times.] Further, this status-passing can be generalized to other cases where you would want to pass labels.

Related

How to write the values in files with different extensions by using the below code?

subroutine iswap (file,b)
implicit none
integer b,m
character*(*) file
m=1
do while (file(m:).ne.' ')
m=m+1
enddo
m=m-1
open(1, File = file(1:m),form='formatted')
write (1,*) b
close(1)
end
subroutine iswap1 (file,b1,c1)
implicit none
integer m,b1,c1
character*6 file
m=1
do while (file(m:).ne.' ')
m=m+1
enddo
m=m-1
call iswap(file(1:m)//'.jk',b1)
call iswap(file(1:m)//'.bk',c1)
end
program callex
implicit none
character*6 unit
call iswap1(unit,2,3)
end
I'm trying to write the code that generates two files ".jk" and ".bk", each containing the value 2 and 3. The code I wrote is not not creating any file. Could you please guide me in correcting this code keeping the code format same? The main program calls "iswap1" subroutine, which then calls "iswap2" subroutine that writes values to files with the extension mentioned in "iswap1" subroutine. Thanks!
Here's the code roughly written in idiomatic modern Fortran:
program callex
implicit none
character(len=80) :: fname = "thefile"
call iswap1(fname,2,3)
contains
subroutine iswap (file,b)
implicit none
integer, intent(in) :: b
character(len=*), intent(in) :: file
integer :: unit
open(newunit=unit, File = file ,form='formatted')
write (unit,*) b
close(unit)
end subroutine iswap
subroutine iswap1 (file,b1,c1)
implicit none
integer, intent(in) :: b1,c1
character(len=*), intent(in) :: file
call iswap(trim(file)//'.jk',b1)
call iswap(trim(file)//'.bk',c1)
end subroutine iswap1
end program callex
Some notable changes from your original version:
Use contained procedures to get argument checking.
character variables declared with length per modern syntax.
Initial character variable, fname initialized (and made a bit longer because why not). Also I initialized fname to a non-empty string because otherwise on Unix type systems the generated files will be hidden as the name would start with ..
Dummy character variables declared with len=* meaning they get the length from the caller.
Declare intent for dummy arguments.
Use trim instead of a loop to get rid of trailing spaces.
Use NEWUNIT= when opening units rather than manually allocating unit numbers.

How to use procedure pointers for subroutines with different number of arguments

I'm developing a Fortran program for scientific computing. I want to use procedure pointers to assign the boundary conditions in the problem, shown in the following main program
program main
use boundary
implicit none
bc1 => boundaryA
bc2 => boundaryB
bc3 => boundaryC
call comp_boundary
end program
I define all the boundary operations "boundaryA/B/C" in a "boundary" module
module boundary
implicit none
procedure(boundary_type), pointer :: bc1,bc2,bc3
abstract interface
subroutine boundary_type(i)
integer :: i
end subroutine
end interface
contains
subroutine boundaryA(i)
integer :: i
print*, 'Boundary A at ',i
end subroutine
subroutine boundaryB(i)
integer :: i
print*, 'Boundary B at ',i
end subroutine
subroutine boundaryC(i)
integer :: i
print*, 'Boundary C at',i
end subroutine
subroutine comp_boundary
call bc1(1)
call bc2(2)
call bc3(3)
end subroutine
end module
This works well.
But my question is that if, say, boundaryC has not one input argument, but two, then my definition for the abstract interface boundary_type doesn't work now.
Is that possible to use the procedure pointer to deal with this case? Or any other way around?
You could achieve this with an OPTIONAL argument. This is more an academic solution as there is always conservation of misery. As the comment of High Performance Mark states, your decision to use one or two arguments will need to be made somewhere.
Nonetheless, the OPTIONAL argument would require to add this too all subroutines and could therefore be not really the solution you request as all subroutines are essentially changed. It is essentially the same solution you gave, with just different set of procedure arguments.
MODULE boundary
IMPLICIT NONE
PROCEDURE(boundary_type), POINTER :: bc1,bc2
ABSTRACT INTERFACE
SUBROUTINE boundary_type(i,j)
INTEGER :: i
INTEGER, OPTIONAL :: j
END SUBROUTINE boundary_type
END INTERFACE
CONTAINS
SUBROUTINE boundaryA(i,j)
INTEGER :: i
INTEGER, OPTIONAL :: j
PRINT *, 'Boundary A at ',i
END SUBROUTINE boundaryA
SUBROUTINE boundaryB(i,j)
INTEGER :: i
INTEGER, OPTIONAL :: j
PRINT *, 'Boundary B at ',i,j
END SUBROUTINE boundaryB
SUBROUTINE comp_boundary
CALL bc1(1)
CALL bc2(2,3)
END SUBROUTINE comp_boundary
END MODULE boundary
Note: the subroutine boundaryB must always be called with both arguments as no check is done for the availability of j (using PRESENT)

Is it possible to dynamically change the name of a read Fortran namelist?

I would like to do something like:
(in pseudo code)
For all x in my_namelist_list
Read(unit_number,nml=x)
...
some other operations
...
end
What is the type of a namelist? Is it possible to pass it as an argument?
subroutine generic_reading_of_namelist(namelist_argument)
Does someone knows any workaround solution to manipulate many name lists all together?
In short: namelist has no type because it is a statement, not a variable declaration. This means its use is quite limited: only as the nml = argument to I/O operations.
It is also a very old feature, as discussed here, whose functionality has changed little since its introduction.
So, what is most straightforward depends on what exactly you want to do. You could try to use one namelist for multiple purposes, for example, or design your own input file format for which you have a custom reading routine.
Edit:
Suppose you have an abstract type and some extensions in several modules:
module absTypeMod
implicit none
type, abstract :: absType
integer :: i = 0
contains
procedure(info), pass(this), public, deferred :: info
end type
abstract interface
subroutine info(this)
import :: absType
class(absType), intent(in) :: this
end subroutine
end interface
end module
module typeAMod
use absTypeMod
implicit none
type, extends(absType) :: typeA
private
integer :: j = 1
contains
procedure :: info => info_A
end type
contains
subroutine info_A(this)
class(typeA), intent(in) :: this
print*, 'i:', this%i, 'j:', this%j
end subroutine
end module
module typeBMod
use absTypeMod
implicit none
type, extends(absType) :: typeB
private
real :: k = 2.0
contains
procedure :: info => info_B
end type
contains
subroutine info_B(this)
class(typeB), intent(in) :: this
print*, 'i: ', this%i, ' k: ', this%k
end subroutine
end module
You can then make a factory module, which provides the logic for instantiating the concrete extensions based on some input. An example:
module factoryMod
use typeAMod
use typeBMod
private
public :: absType, factory
contains
subroutine factory(t, switch)
class(absType), allocatable, intent(out) :: t
character(*), intent(in) :: switch
select case(switch)
case('A')
allocate(typeA :: t)
case('B')
allocate(typeB :: t)
end select
end subroutine
end module
And use it in a test program:
program test
use factoryMod
implicit none
class(absType), allocatable :: foo
call factory(foo, 'A')
call foo%info() ! Output: i: 0 j: 1
call factory(foo, 'B')
call foo%info() ! Output: i: 0 k: 2.000000
end program
You can make this as fancy as you wish. I use here a simple string to select the actual type to allocate in factory, but I've also used an implementation where I pass the iunit of a connected input namelist file to the factory. In that case, the factory can use this file not only to determine the type to create, but also to perform a further type-specific setup, whether in the factory itself or in some kind of type-bound initialisation routine (using the same input file).
Also note that this example factory is a subroutine and not a function, since the assignment foo = factory('A') is not allowed in Fortran 2003. It is no longer prohibited by F2008, but support is currently not universal.

Does Fortran 95 allow two subroutines to have the same name if the argument lists are different?

Does the Fortran 95 standard allow two subroutines (or functions) to have the same name if the argument lists have different lengths? For example,
subroutine a(i)
! code here
end subroutine a
subroutine a(j,k)
! code here
end subroutine a
Not literally as given in the question, but by using an interface:
module a_wrapper
interface a
module procedure a_1
module procedure a_2
end interface
contains
subroutine a_1(i)
! code here
end subroutine a
subroutine a_2(j,k)
! code here
end subroutine a
end module
program test
use a_wrapper, only: a
call a(.....)
end program
See also my answer to this post: Passing different set of variables in a FORTRAN subroutine or M.S.B.'s answer on this post: how to write wrapper for 'allocate'

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.