Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran DEALLOCATE

I am currently trying to code a little subroutine in Fortran to deallocate all allocated variables in memory when my program comes to an error, i.e., a failed to load file or an inexistent needed file. At this point, execution must be terminated, but not all allocatables are necessarily allocated (it depends on where on the code the error appeared), so i can't make a cleanup deallocating all of them.

My current approach is the following:

SUBROUTINE Cleanup(A)

    REAL(8), ALLOCATABLE, DIMENSION(:) :: A

    IF (ALLOCATED(A)) THEN
        DEALLOCATE(A)
    END IF

END SUBROUTINE

and call "Cleanup" for every allocatable. The problem with this is that not all my variables are dimension-1. I have up to three dimensions in some of them.

I first thought about writing 3 different subroutines for different dimensions and using overloading, but this do not seems to be very elegant.

Then it came to my mind that maybe i could pass a pointer instead the actuall argument A, but i've googled and it seems you can't deallocate a target variable trough a pointer.

Any ideas about how to do this properly?

Thanks.

like image 560
dvilela Avatar asked May 08 '13 08:05

dvilela


People also ask

What is deallocate in Fortran?

Purpose. The DEALLOCATE statement dynamically deallocates allocatable objects and pointer targets. A specified pointer becomes disassociated, while any other pointers associated with the target become undefined.

What is the meaning of deallocate?

(transitive) To remove from the set of resources put aside for (allocated to) a particular user or purpose. Empty out your locker; it will be deallocated at the end of the day.


1 Answers

My approach to this would use a combination of the following:

  • As of Fortran 95, all local un-saved allocatable variables that are allocated when a procedure finishes are automatically deallocated. Whether this is applicable depends on how your DLL is called, and hence whether you can actually structure things such that all your allocatables are unsaved locals.

  • As of Fortran 2003 (or Fortran 95 + the allocatable TR - this language level is widely supported amongst maintained Fortran compilers) allocatable actual arguments passed to INTENT(OUT) allocatable dummy arguments will be automatically deallocated before the procedure starts execution. Your Cleanup routine in the question just needs to add the declaration of the dummy argument as INTENT(OUT) and then there's no need for the IF test or DEALLOCATE. You still need to write the routine for each type and rank that you need to clean up.

  • Similar to the previous, allocatable components of derived type variables passed to an INTENT(OUT) dummy argument will be automatically deallocated. So you may be able to collect all your allocatable variables together as components in an object of derived type. Cleanup then simply involves passing that object to a procedure with an INTENT(OUT) dummy. INTENT(OUT) here also resets components that have default initialization back to their "default" value. Perhaps there's other cleanup that you need to manually do at this point too (close files, etc).

  • An alternative approach, again using derived types with all your variables as components, is to make the derived type object itself allocatable. When you need to cleanup, simply deallocate that one object - components of it will be automatically deallocated. Fortran 2003 allows for a final procedure to be triggered from this sort of event if you have additional other cleanup to do at this point.

A derived type approach also makes it easy to have multiple instances of whatever your DLL supports independently active at the one time (you just have multiple objects of derived type).

Examples of the derived type approach, given:

TYPE MyType
  REAL, ALLOCATABLE :: variable_one(:)
  INTEGER, ALLOCATABLE :: variable_two(:)
  ...
END TYPE MyType

INTENT(OUT) dummy

TYPE(MyType) :: object
ALLOCATE(object%variable_one(xxx))
ALLOCATE(object%variable_two(yyy))
...
IF (things_have_gone_wrong) CALL Cleanup(object)
...
SUBROUTINE Cleanup(arg)
  TYPE(MyType), INTENT(OUT) :: arg
END SUBROUTINE Cleanup

ALLOCATABLE object.

TYPE(MyType), ALLOCATABLE :: object
ALLOCATE(object)
ALLOCATE(object%variable_one(...))
ALLOCATE(object%variable_two(...))

...
IF (things_have_gone_wrong) DEALLOCATE(object)
like image 100
IanH Avatar answered Sep 22 '22 14:09

IanH