Question

I have a question regarding assigning Fortran90 derived types and pointers at runtime. I want to pass a derived variable type to a subroutine after the code reads an input file. So depending on the input I pass the appropriate data type. Let me explain:

I have two modules:

Module A_mod and Module B_mod. Each has it's own unique data type and subroutines. For example:

Module A_mod

type A
real :: x, y
end type

contains

subroutine FunA(me)
type (A), intent(in) :: me
<do stuff>
end subroutine

End module A_mod

Module B_mod is a mirror of the above with B replacing A (also the data type B has x and y defined as integers).

I also have a third module that has this interface:

interface fun
modular procedure funA, funB
end interface

Here is my problem. The user via an input file determines which module subroutine to use. How can I make a generic pointer that gets associated at runtime? Or something similar that doesn't require pointers.

For example:

type (?) :: pt
Call fun(pt)

where after the program reads the input file it picks the correct data type to be sent to the interfaced subroutine "fun". So the type is unknown until runtime.

If Fortran would let me declare a variable in my execution portion of code it would look like this for example

IF(input.EQ."A") THEN
type(A) :: pt
ELSE
type(B) :: pt
END IF

CALL fun(pt)

Any suggestion would be appreciated !!

Thank you

Was it helpful?

Solution

This is difficult to do cleanly in Fortran 90. It is straight forward in Fortran 2003.

Resolution of the procedure to call when the generic reference fun is encountered (in CALL fun(pt)) is done at compile time, based on the declared type of pt.

If you are limited to Fortran 90, then effectively you will need to maintain a flag of some sort that indicates at runtime which particular derived type you want to work with, have a named object for each of type A and type B, and everytime you want to reference fun have an IF construct that selects the correctly named argument.

(If the size of the objects is significant you can arrange for them to have common storage.)

Something like:

TYPE(A) :: pt_A
TYPE(B) :: pt_B
...
IF (input .EQ. 'A') THEN
  CALL fun(pt_A)
ELSE
  CALL fun(pt_B)
END IF

In F2003, you would define a common parent type, that had a specific binding named fun. pt would then be a polymorphic allocatable object, allocated based on input to either type A or type B as appropriate.

TYPE :: Parent
CONTAINS
  PROCEDURE(parent_Fun), DEFERRED :: Fun
END TYPE Parent

ABSTRACT INTERFACE
  SUBROUTINE parent_Fun(obj)
    IMPORT :: Parent
    IMPLICIT NONE
    CLASS(Parent), INTENT(IN) :: obj
  END SUBROUTINE parent_Fun
END INTERFACE

TYPE, EXTENDS(Parent) :: A
  REAL :: x, y
CONTAINS
  PROCEDURE :: A => A_Fun
END TYPE A

TYPE, EXTENDS(Parent) :: B
  INTEGER :: x, y
CONTAINS
  PROCEDURE :: B => B_Fun
END TYPE B

CLASS(Parent), ALLOCATABLE :: pt
...
IF (input .EQ. 'A') THEN
  ALLOCATE(A:: pt)
ELSE
  ALLOCATE(B:: pt)
END IF
...
CALL pt%Fun()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top