elfsummer
elfsummer

Reputation: 167

Intel Fortran error "allocatable array or pointer is not allocated"

When I tried to run a huge Fortran code (the code is compiled using Intel compiler version 13.1.3.192), it gave me error message like this:

... 
Info[FDFI_Setup]: HPDF code version number is  1.00246
forrtl: severe (153): allocatable array or pointer is not allocated
Image              PC                Routine            Line        Source
arts               0000000002AD96BE  Unknown               Unknown  Unknown
arts               0000000002AD8156  Unknown               Unknown  Unknown
arts               0000000002A87532  Unknown               Unknown  Unknown
...

Nonetheless, if I insert a small write statement (which is just to check the code, not to disturb the original purpose of the code) in one of the subroutines as the following (I couldn't put all the codes since they are too huge):

    ...
    endif
    call GetInputLine(Unit,line,eof,err)
  enddo

  if(err) return

  ! - [elfsummer] 20140815 Checkpoint 23
  open(unit = 1, file = '/bin/monitor/log_checkpoint',status='old',position='append')
  write(1,*) "BEFORE checking required keys: so far so good!"
  close(1)

  ! check required keys
  ! for modes = 2,3, P and T are the required keys
  if(StrmDat%ModeCI==2.or.StrmDat%ModeCI==3) then
  ...

then suddenly, the error message shown above disappears and the code can run correctly! I also tried to insert such write statements in other locations in the source code but the above error message still exists.

According to Intel's documentation:

severe (153): Allocatable array or pointer is not allocated FOR$IOS_INVDEALLOC. A Fortran 90 allocatable array or pointer must already be allocated when you attempt to deallocate it. You must allocate the array or pointer before it can again be deallocated. Note: This error can be returned by STAT in a DEALLOCATE statement.

However, I couldn't see any relations between the error and the "write statements" I added to the code. There is no such "allocate" command in the location I add the write statements.

So I am quite confused. Does anybody know the reasons? Any help is greatly appreciated!!

With traceback option, I could locate the error source directly:

    subroutine StringRead(Str,delimiter,StrArray,ns)   ! [private] read strings separated by    delimiter
    implicit none
    character*(*),intent(in)    :: Str
    character*(*),intent(in)    :: delimiter
    character*(*),pointer       :: StrArray(:)
    integer,intent(out)         :: ns
! - local variables
    character(len=len(Str))     :: tline
    integer                     :: nvalue,nvalue_max
    character(len=len(StrArray)),pointer:: sarray(:),sarray_bak(:)
    integer                     :: len_a,len_d,i

    ! deallocate StrArray
    if(associated(StrArray)) deallocate(StrArray)

The error, according to the information the traceback gave me, lies in the last statement shown above. If I comment out this statement, then the "forrtl: severe (153)" error would disappear while new errors being generated... But still, I don't think this statement itself could go wrong...It acts as if it just ignores the if... condition and directly reads the deallocate commend, which seems weird to me.

Upvotes: 2

Views: 5099

Answers (2)

DrOli
DrOli

Reputation: 1083

Sounds like some of the earlier comments give the general explanation. However,

1) Is StrArray(:) an Intent(out)? That is, are you reading the file's lines into StrArray() in the s/r, with the hope of returning that as the file's content? If so, declare it as an (Out), or whatever it should be.

2) Why is StrArray() a Pointer? Does it need to be a Pointer? If all you want is file content, you may be better off using a non-Pointer.

You may still need an Allocatable, or Automatic or something, but non-Pointers are easier in many cases.

3) If you must have StrArray(:) as a Pointer, then its size/shape etc must be created prior to use. If the calling sequence ACTUAL Arg is correctly defined (and if StrArray() is Intent(In) or Intent(InOUT), then that might do it.

By contrast, if it is an (Out), then, as with all Pointer arrays, it must be FIRST Allcoated() in the s/r.

If it is not Allocated somewhere early on, then it is undefined, and so the DeAllocate() fails, since it has nothing to DeAlloc, hence Stat = 153.

4) It is possible that you may wish to use this to read files without first knowing the number of lines to read. In that case, you cannot (at least not easily), Allocate StrArray() in advance, since you don't know the Size. In this case, alternate strategies are required.

One possible solution is a loop that simple reads the first char, or advances somehow, for each line in the file. Have the loop track the "sum" of each line read, until EOF. Then, you will know the size of the file (in terms of num lines), and you then allocate StrArray(SumLines) or something. Something like

SumLines = 0
Do i=1, ?? (or use a While)
    ... test to see if "line i" exists, or EOF, if so, Exit
    SumLines = SumLines + 1
End Do

It may be best to do this in a separate s/r, so that the Size etc are known prior to calling the FileRead bits (i.e. that the file size is set prior to the FileRead s/r call).

However, that still leaves you with the problem of what Character(Len) to use. There are many possible solutions to this. Three of which are:

a) Use max length, like Character(Len = 2048), Intent(Out), or better yet, some compile time constant Parameter, call it MaxLineWidth

This has the obvious limitation to lines that <= MaxLineWidth, and that the memory usage may be excessively large when there many "short lines", etc.

b) Use a single char array, like Character(Len = 1), Intent(Out) :: StrArrayChar(:,:)

This is 2-D, since you need 1 D for the chars in each line, and the 2nd D for the lines.

This is a bit better compared to a) since it gives control over line width.

c) A more general approach might rely on a User Defined Type such as:

Type MyFileType
    Character(Len=1), Allocatable   :: FileLine(:)  ! this give variable length lines, but each "line" must be allocated to the length of the line
End Type MyFileType

Then, create an array of this Type, such as:

Type(MyFileType), Allocatable   :: MyFile(:)    ! or, instead of Allocatable, can use Automatic etc etc

Then, Allocate MyFile to Size = num lines

... anyway, there are various choices, each with its own suitability for varying circumstances (and I have omitted much "housekeeping" re DeAllocs etc, which you will need to implement).

Incidentally, c) is also one possible prototype for "variable length strings" for many Fortran compilers that don't support such explicitly.

Upvotes: 1

M. S. B.
M. S. B.

Reputation: 29401

You could have a bug in which you are illegally writing to memory and damaging the structure that stores the allocation information. Changing the code might cause the memory damage to occur elsewhere and that specific error to disappear. Generally, illegal memory accesses typically occur two ways in Fortran. 1) illegal subscripts, 2) mismatch between actual and dummy arguments, i.e., between variables in call and variables as declared in procedures. You can search for the first type of error by using your compiler's option for run-time subscript checking. You can guard against the second by placing all of your procedures in modules and useing those modules so that the compiler can check for argument consistency.

Upvotes: 3

Related Questions