jornada
jornada

Reputation: 23

OOP Fortran: saving pointers to intent(IN) variables

I have a Fortran module that I want to organize following OOP philosophy as much as possible, while still making it compatible with Fortran 2003. This module basically: (a) allocs/frees temporary array buffers, and (b) provides a function do_F which operates on some data. This function do_F uses these temporary buffers, but also depends several auxiliary types.

It is clear to me that I should put the buffers into a type, and initialize/free when appropriate. However, since each call to do_F takes several arguments, I am sure what is the best design strategy to use.

To be more concrete, consider the following implementations:

  1. Pass a large number of types every time do_F is called

    type object_t
        ! lots of private buffers
        real, allocatable :: buf1(:,:,:), buf2(:,:,:), etc.
    end type object_t
    
    subroutine init_object(this)
        type(object_t), intent(INOUT) :: this
    
        allocate( this%buf1(..., ..., ...) )
        !...
    end subroutine init_object
    
    subroutine do_F(this, data, aux1, aux2, ..., auxN)
        type(object_t), intent(INOUT) :: this
        type(data_t), intent(INOUT) :: data
        type(aux1_t), intent(IN) :: aux1
        !...
    
        !do stuff on data using the buffers and values stored
        ! in aux1 .. auxN
    end subroutine do_F
    
  2. Save the pointers to the types that do_F needs

     type object_t
        ! lots of private buffers
        real, allocatable :: buf1(:,:,:), buf2(:,:,:), etc.
    
        ! pointers to auxiliary types
        type(aux1_t), pointer :: aux1_ptr
        !...
    end type object_t
    
    subroutine init_object(this, aux1, aux2, ..., auxN)
        type(object_t), intent(INOUT) :: this
        type(aux1_t), intent(IN), target :: aux1
        !...
    
        allocate( this%buf1(..., ..., ...) )
        !...
    
        this%aux1_ptr => aux1
        !...
    end subroutine init_object
    
    subroutine do_F(this, data)
        type(object_t), intent(INOUT) :: this
        type(data_t), intent(INOUT) :: data
    
        !do stuff on data using the buffers and values stored
        ! in this%aux1_ptr .. this%auxN_ptr
    end subroutine do_F
    

My specific questions are:

  1. Is the implementation #2 valid? PGI compiler didn't complain about it, but I heard that an intent(IN) is no longer well defined after the function returns
  2. Is there a performance loss by using this scheme with pointers? Even if I don't write into these aux_ptr's, will the compiler be able to optimize my code as well as in case #1?

Some notes:

  1. The function do_F is called ~100 times, and each call takes a couple of minutes and operates on large arrays.
  2. Apart from do_F, there are also do_G and do_H functions that operate on the same data and use the same aux variables. That is why I wanted to reduce the number of variables passed to the function in the first place.
  3. I don't want to combine all the aux variables into one type, because they are used throughout the rest of a large HPC code.

Thanks!

Upvotes: 0

Views: 384

Answers (1)

Intent IN variables are well defined after return, if they were before the call. The procedure is not allowed to change them. An exception are the values of pointer variables, where you can change the value of the target, but not the association status of the pointer for intent(IN) pointer dummy arguments.

I'm not sure about the efficiency though. Version 2 looks nicer after a quick read.

Upvotes: 2

Related Questions