Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

writing and reading derived types with pointers

j0e
New Contributor I
404 Views

Hi All,

I'm trying to save a write a derived type that contains a pointer to an unformatted file for later reading.  Below is a test version.  The derived type sol in module dType is separate because I'm patching together various Fortran codes (F95 and F77, etc).  The current version of the code "saves" sol1, but it seems to only save the pointer references, not their values, so when sol1 is deallocated, sol2 also becomes unreferenced.  I'm sure my hack on the UDTIO is not correct.

Any help would be appreciated (I'm still trying to figure out UDTIO).  Thanks

-joe

   module dType
      implicit none
      type, public :: sol
         integer:: n
         real(8), pointer:: vec(:)
      end type sol
   end module dType   
   
   module dType_io
      use dType
      implicit none
   contains

   subroutine write_sol(dtv, unit, iostat, iomsg)
      class(sol), intent(in) :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(*), intent(inout)     :: iomsg

      write(unit, iostat=iostat, iomsg=iomsg) dtv%n
      write(unit, iostat=iostat, iomsg=iomsg) size(dtv%vec)
      write(unit, iostat=iostat, iomsg=iomsg) dtv%vec  
   end subroutine write_sol

   subroutine read_sol(dtv, unit, iostat, iomsg)
      class(sol), intent(inout)  :: dtv
      integer, intent(in)                 :: unit
      integer, intent(out)                :: iostat
      character(*), intent(inout)         :: iomsg

      integer allocSize

      ! read is sol type, but allocate pointer space as needed.
      read(unit, iostat=iostat, iomsg=iomsg) dtv%n
      read(unit, iostat=iostat, iomsg=iomsg) allocSize
      allocate( dtv%vec(allocSize) )      
      read(unit, iostat=iostat, iomsg=iomsg) dtv%vec  
   end subroutine read_sol
   end module dType_io
   
   program directAccess
      use dType
      implicit none
      integer, parameter :: dp = kind(0d0)
      type(sol):: sol1, sol2      
      integer solUnit, n, sze
      integer i
      
      sol1%n = 10
      allocate( sol1%vec(sol1%n) )
      sol1%vec = [ (real(i),i=1,sol1%n) ]  
      
      open(newunit=solUnit, file='test.sol', form='unformatted', status='replace', action='write')
      write(solUnit) sol1
      close(solUnit)
      
      open(newunit=solUnit, file='test.sol', form='unformatted', status='old', action='read')
      read(solUnit) sol2
      
      deallocate( sol1%vec ); nullify(sol1%vec) ! this will cause sol2 to lose reference
      
      close(solUnit)      
      stop
   end program directAccess
   
      
      
      

 

0 Kudos
14 Replies
IanH
Honored Contributor II
404 Views

The code doesn't have the necessary declarations of the generic bindings or interfaces that specify that read_sol and write_sol are the procedures implementing defined IO for your type - the code is missing something like

INTERFACE READ(UNFORMATTED)
  MODULE PROCEDURE read_sol
END INTERFACE READ(UNFORMATTED)

and similarly for the WRITE(UNFORMATTED) interface.

The code should not compile without these.

You want to be using the very latest compiler (and perhaps even a bit later than that) if you are using UDDTIO.

(Edit to later add... I tried the current beta on the code, and I see it also fails to diagnose the body-text requirement for defined input/output of an object of derived type with pointer components.

Unrelated to UDDTIO, but I can't help myself - note that DEALLOCATION of a pointer also dissociates it - the nullify after the deallocate is just wearing your keyboard out prematurely.)

0 Kudos
jimdempseyatthecove
Honored Contributor III
404 Views

You should also modify your read and write routines to handle the case where the pointer is NULL.

e.g. On write, when pointer is null, write 0 for size and do not take size of the array.
On read, when allocSize is 0, nullify the pointer instead of allocating the pointer.

Jim Dempsey

0 Kudos
j0e
New Contributor I
404 Views

Thanks Ian and Jim. As always, very helpful!!! I also found Ian's previous post here https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/621651#comment-1864744 to be very useful.

BTW, I am using the latest Intel compiler and the interface statements solved the problem.

cheers,

-joe

0 Kudos
j0e
New Contributor I
404 Views

I guess I spoke too soon.  It appears when the size of the pointer becomes large (> than around 16390 elements), the write works OK, but when the read is executed it produces the IO errors:

On Write: iostat =    0 iomsg = OK
On Read: iostat =   67 iomsg = input statement requires too much data, unit -130, file C:\Users\jvallino\Projec

The read error occurs when it attempts to: read(unit, iostat=iostat, iomsg=iomsg) dtv%vec(1:allocSize)  As far as I can tell, IO limits are not being violated.  I'm guessing it is something simple, but I'm currently baffled.  Code is below.

   module dType
      implicit none
      type, public :: sol
         integer:: n
         real(8), dimension(:), pointer:: vec
      end type sol
   end module dType   
   
   module dType_io
      use dType
      implicit none
      interface read(unformatted)
         procedure read_sol
      end interface read(unformatted)
      interface write(unformatted)
         procedure write_sol
      end interface write(unformatted)
      
   contains
   subroutine write_sol(dtv, unit, iostat, iomsg)
      class(sol), intent(in) :: dtv
      integer, intent(in)             :: unit
      integer, intent(out)            :: iostat
      character(*), intent(inout)     :: iomsg

      write(unit, iostat=iostat, iomsg=iomsg) dtv%n
      write(unit, iostat=iostat, iomsg=iomsg) size(dtv%vec)
      write(unit, iostat=iostat, iomsg=iomsg) dtv%vec(1:size(dtv%vec))  
   end subroutine write_sol

   subroutine read_sol(dtv, unit, iostat, iomsg)
      class(sol), intent(inout)  :: dtv
      integer, intent(in)                 :: unit
      integer, intent(out)                :: iostat
      character(*), intent(inout)         :: iomsg

      integer allocSize

      ! read is sol type, but allocate pointer space as needed.
      read(unit, iostat=iostat, iomsg=iomsg) dtv%n
      read(unit, iostat=iostat, iomsg=iomsg) allocSize
      allocate( dtv%vec(allocSize) )      
      read(unit, iostat=iostat, iomsg=iomsg) dtv%vec(1:allocSize)  
   end subroutine read_sol
   end module dType_io
   
   program testUDDTIO
      use dType
      use dType_io
      implicit none
      integer, parameter :: dp = kind(0d0)
      type(sol):: sol1, sol2      
      integer solUnit, n, sze
      character*80 iomsg
      integer i, iostat
      
      sol1%n = 16390
      allocate( sol1%vec(sol1%n) )
      sol1%vec = [ (real(i),i=1,sol1%n) ]  
      iomsg = 'OK'
      open(newunit=solUnit, file='test.sol', form='unformatted', status='replace', action='write')
      write(solUnit, iostat=iostat,  iomsg=iomsg) sol1
      write(*,'(a,i4,2a)') 'On Write: iostat = ', iostat,' iomsg = ',trim(iomsg)
      close(solUnit)
      
      iomsg = 'OK'
      open(newunit=solUnit, file='test.sol', form='unformatted', status='old', action='read')
      read(solUnit, iostat=iostat,  iomsg=iomsg) sol2
      write(*,'(a,i4,2a)') 'On Read: iostat = ', iostat,' iomsg = ',trim(iomsg)

      deallocate( sol1%vec )
      
      close(solUnit)      
      stop
   end program testUDDTIO

The file produced during the write appears to be the correct size.  Also, when sol1%n is large enough to cause the read error, only the first 1022 elements are read into dtv%vec.

Thanks Again!

0 Kudos
jimdempseyatthecove
Honored Contributor III
404 Views

Hopefully your last code posting will reproduce the error for an Intel software support person. They should be able to investigate the issue with a reproducer. Please provide all the particulars: Compiler version, options used, 32/64-bit build, O/S.

Jim Dempsey

0 Kudos
andrew_4619
Honored Contributor II
404 Views

You need to allocate sol2 before the read or have the compiler flag /standard-semantics for it to auto-allocate on read.

0 Kudos
jimdempseyatthecove
Honored Contributor III
404 Views

Andrew,

I believe the auto-allocate only applies to assignment (=) not reads. The option enabling this is realloc_lhs. For READ, the buffer argument is not an LHS entity.

Jim Dempsey

0 Kudos
j0e
New Contributor I
404 Views

Even if you allocate sol2%vec prior to reading (which would defeat the usefulness of UDDTIO it would seem) the problem still occurs when the size exceeds ~16390 elements.  I did not try changing compiler options.

Using ifort 16.0.3.207 (build 20160415), x64 compiler

ifort /debug:full /Od /warn:interfaces /traceback /check:bounds /check:stack /libs:static /threads /dbglibs /Qmkl:parallel derivedTypeWriteRead.f90

Build and run on Windows 10.  

On a Linux box running version 16.0.2 20160204 of ifort, compiled with just "ifort derivedTypeWriteRead.f90" the exact same problem occurs.

For now, I've dropped trying to use UDDTIO and just went the non object route.

Thanks for everyone's help!

 

0 Kudos
andrew_4619
Honored Contributor II
404 Views

Your example works with /standard-semantics for 18000 which is what I tested.on an x32 build.

 

 

 

0 Kudos
andrew_4619
Honored Contributor II
404 Views

Actually I take that back, it only reads the first 1022 elements....

0 Kudos
j0e
New Contributor I
404 Views

OK, cause I just tried standard-semantics on both win and linux boxes and it did not work, but thanks for trying

0 Kudos
IanH
Honored Contributor II
404 Views

It is a compiler runtime bug.  You can make it go away for the specific example if you increase things like the block size used for input/output (e.g. set FORT_BLOCKSIZE=256000 before running the program).

(Reallocation on assignment only applies when assigning to allocatables.  There are no allocatables in the program.)
 

0 Kudos
Kevin_D_Intel
Employee
404 Views

Thank Joe, Ian. I escalated the issues to Development.

(Internal tracking id: DPD200412514 - not diagnosing body-text requirement for defined input/output of an object of derived type with pointer components)

(Internal tracking id: DPD200412516 - Run-time iostat=67 reading > ~16390 elements w/UDDTIO)

0 Kudos
Kevin_D_Intel
Employee
404 Views

DPD200412514, the missed diagnosis, will be fixed in a future major release (not the one later this year).

0 Kudos
Reply