3

I'm attempting to create global-ish-ly available allocatable array of a set of derived types that share inheritance with a single object. Fortran does not seem to make this very easy. The below is what I have so far.

First the derived types and module with the allocatable array.

Module Environment
    use Entity_M
    type(Entity_C), dimenion(:), allocatable :: objects
End Module Environment

Module Entity_M
    type Entity_T
        integer :: id
        real*8 :: time
        real*8, dimension(3) :: currPos

        type(TrajectoryDatum), dimension(:), allocatable :: trajTable

    end type Entity_T

    type Entity_C
        class(Entity_T), pointer :: e
    end type Entity_C

    type, extends(Entity_T) :: Aircraft_T
        real*8 :: altitude
    end type Aircraft_T

    type, extends(Entity_T) :: Missile_T
        integer :: targetID
    end type Missile_T

End Module Entity

Now the main program

Program Main

    use Initialization
    use Environment
    use Entity_M

    call simInit(3)
    write(*,*) objects%trajTable !<---- this does not persist

    call runSim()

End Program Main

The code with the issue

Module Initialization

    use Entity_M

    contains

    subroutine simInit(numOfObjects)

        integer, intent(in) :: numOfObjects

        call objectsInit(numOfObjects)
        call launchersInit()

    end subroutine simInit


    subroutine objectsInit(numOfObjects)

        use Environment

        integer, intent(in) :: numOfObjects

        !local
        type(Aircraft_T) :: aircraft
        integer :: i

        allocate(objects(numOfObjects)

        do i = 1, numOfObjects

            aircraft%trajTable = getTrajectoryData()

            call allocatePointer(objects(i)%e, aircraft)

        end do

    end subroutine objectsInit

    subroutine allocatePointer(c, t)

        class(Entity), pointer, intent(out) :: c
        type(Aircraft), target, intent(in) :: t

        c => t

    end subroutine allocatePointer

End Module Initialization

This above just example code written on a computer that doesn't have a compiler. I did my best and hopefully if there are typos they are few. I did my best to mirror the structure of the original code.

The problem is that the field "objects%trajTable" goes back to a undefined pointer after it leaves the "objectsInit" subroutine. The other values like time, id, and currPos are still correct. How can I correct this?

I am using Visual Studio 2012 and Intel Visual Fortran 2015.

2
  • 1
    It is always better to submit working example. I believe that you need use Entity in module Environment. Apart from that, the problem that I see is that aircraft in objectsInit is a local variable that disapear when you get out of that subroutine. So associating it as a target to your pointer variable will bot help you. The stack memory is used for some other things when the subroutine returns. And so you have a problem there. Commented Jul 15, 2015 at 19:37
  • I agree working example is better. But the code is on a classified machine (and large swaths of it are classified) and I don't really have a way to compile on my unclassified one. I'll fix a couple of the typos mentioned now. Commented Jul 15, 2015 at 20:15

1 Answer 1

2

Because the program has many overlapping names (like Aircraft and aircraft, which are regarded as the same in Fortran), I have attached "_t" to all the types (e.g., Aircraft to Aircraft_t etc) and "_m" to all the module names (e.g., Entity to Entity_m) to make the program work (at least formally).

More importantly, as @innoSPC commented above, type(Aircraft) :: aircraft is a local variable, so I think a pointer associated to it becomes undefined after exiting objectsInit(). The code works if

call allocatePointer( objects( i )% e, aircraft )

is replaced by

allocate( objects( i )% e, source=aircraft )

so that each objects( i )% e is given an independent memory having the type of Aircraft_t, with the contents of aircraft copied to it.


Edit Here is a minimum example that I used for test.

Module Entity_m
    implicit none

    type Entity_t   !! base type                                                    
        integer :: trajTable( 2 )
    endtype

    type, extends(Entity_t) :: Aircraft_t
        real*8 :: altitude
    endtype

    type, extends(Entity_t) :: Missile_t  !! dangerous...
        integer :: targetID
    endtype

    type Entity_c   !! container type                                               
        class(Entity_t), pointer :: e
    endtype

    type(Entity_c), allocatable :: objects(:)

contains

    subroutine objectsInit( numObj )

        integer :: numObj

        !local                                                                      
        type(Aircraft_t) :: aircraft
        type(Missile_t)  :: missile
        integer :: i

        allocate( objects( numObj ) )

        do i = 1, numObj

            if ( mod( i, 2 ) == 1 ) then
                aircraft% trajTable(:) = i
                aircraft% altitude = 10.0d0 * i

                allocate( objects( i )% e, source= aircraft )
            else
                missile% trajTable(:) = 10000 * i
                missile% targetID = -100 * i

                allocate( objects( i )% e, source= missile )  !! missile loaded !!
            endif
        enddo

    endsubroutine

EndModule

Program Main
    use Entity_m

    call objectsInit( 3 )

    do i = 1, 3
        print *, objects( i )% e% trajTable(:)  !! access members of base type      

        select type ( t => objects( i )% e )    !! access members of derived type   
            type is ( Aircraft_t ) ; print *, t% altitude
            type is ( Missile_t )  ; print *, t% targetID
        endselect
    enddo

EndProgram
Sign up to request clarification or add additional context in comments.

4 Comments

I'm going to try that right now. I have been looking for something like that for the better part of 2 days. Can you link to some documentation for me?
That is excellent. I knew the issue was the the thing being pointed to was going out of scope I just couldn't find any way to allocate like that. Basically the equivalent of the new keyword in c based languages.
@TheComposer Here are some documentation from PGI part 1 2 3 4 where part 2 explains allocate() with source=. Btw I tried "parametrized type" explained in part 3 before, but it did not work with gfortran4.8 yet...
Thank you. I had found part 1. It is what got me this far. I hadn't come across the other parts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.