Silverfrost Forums

Welcome to our forums

SDBG64 with derived types

30 Apr 2024 2:14 #31324

How to see values of derived type variables in SDBG?

type cell
  real, allocatable, dimension (:) :: var
end type cell
type (cell) species(0:3)


do i=0,3
  n = i + 1
  if(allocated(species(i)%var )) deallocate(species(i)%var)
  allocate (species(i)%var(n))

  species(i)%var = n
enddo

end
30 Apr 2024 3:34 #31325

Double click on SPECIES in the Variables window. Then double click on SPECIES(0):TYPE(CELL) in the SPECIES window. Then double click on var: REAL*4 POINTER ::(1) in the SEPCIES(0) window.

2 May 2024 11:50 #31326

Thanks, i was initially confused with 'Syntax error' messages and absence of bubble help (like with usual arrays) doing that and thought this option does not work at all

2 May 2024 11:34 #31327

10 years ago i tried to use derived types with 32bit FTN95 and failed. Crashes, access violations, irrational behavior....Now i need to allocate variable number of entries in the array (imagine some allocatable 2D array with variable number of elements of each row, every call different) and for that allocation of standard arrays does not work (Standard does not allows that by some reason, that does not work with other compilers too) and hence i need to use derived types again. Why derived types allow that functionality is beyond me.

And i am failing again by multiple reasons. Here is first one. Is anything wrong with this text? It is the same one as above which works, but this time the allocation takes place inside the function in the module not in the main program. It wrongfully tells that array is allocated and then it tries to deallocate it and fails. I compile FTN95 aaa.f95 /link /debug /undef /64 >zzz

module mod
type cell
  real, allocatable, dimension (:) :: var
end type cell
type (cell) species(0:3)

Contains

integer function fun1 ()
do i=0,3
  n = i + 1
  if ( allocated(species(i)%var )) deallocate(species(i)%var)
  allocate (species(i)%var(n))
  species(i)%var = n
enddo
fun1=2
end function fun1

end module
!==================
Program Prg
use mod
integer, external :: fun2

jj = fun1 ()
jj = fun2 ()

end program
!========================
integer function fun2 ()
use mod
  print*, species(0)%var(2) 
fun2=2
end function fun2

Gfortran runs this no problem.

Another example for which i am still preparing a demo, allocates derived type array multiple times and does not ends up with the error despite i do not deallocate this array. But then i change array dimension and it crashes

3 May 2024 8:10 #31328

species(0)%v is allocated just one element species(0)%v(1) so when it comes to the print, species(0)%var(2) is out of range.

species(0:3) should be initialised before testing for ALLOCATED. For example FTN95 allows...

do i = 0,3 nullify(species(i)%var) end do

but off hand I don't know the 'right' way to do this.

3 May 2024 1:14 #31329

Looks like nullify could be that missing piece in the puzzle...Thanks Paul

3 May 2024 1:56 #31330

Dan, your program is almost working. All that you have to do is to make sure that subscript bounds are honored, or, equivalently, allocate arrays with sufficient size.

Here is a fixed-up version:

module mod
type cell
  real, allocatable, dimension (:) :: var
end type cell
type (cell) species(0:3)

Contains

integer function fun1 ()
do i=0,3
  n = i + 1
  if ( allocated(species(i)%var )) deallocate(species(i)%var)
  allocate (species(i)%var(n))
  print *,'species(',i,') allocated with size ',n
  species(i)%var = n
enddo
fun1=2
end function fun1

end module
!==================
Program Prg
use mod
integer, external :: fun2

jj = fun1 ()
jj = fun2 ()

end program
!========================
integer function fun2 ()
use mod
integer i
  do i = 0,3
     print*, species(i)%var(i+1)
  end do
  fun2=2
end function fun2
4 May 2024 5:13 #31331

I suggest that an enhanced version of the derived type might be more functional, as in the example below

module mod
type cell
  integer :: n = 0
  real, allocatable, dimension (:) :: var
end type cell
type (cell) species(0:3)

Contains

integer function fun1 ()
do i=0,3
  n = i + 1
  if ( allocated(species(i)%var )) deallocate(species(i)%var)
  allocate (species(i)%var(n))
  print *,'species(',i,') allocated with size ',n
  species(i)%n = n
  species(i)%var = atan (1.0) * n
end do
fun1=2
end function fun1

end module
!==================
Program Prg
use mod
integer, external :: fun2

jj = fun2 ()
jj = fun1 ()
jj = fun2 ()

end program
!========================
integer function fun2 ()
use mod
integer i
  do i = 0,3
     n = species(i)%n
     if ( n > 0) then
       print*, i, n, species(i)%var(n)
     else
       print*, i, n
     end if
  end do
  fun2=2
end function fun2
4 May 2024 7:50 (Edited: 4 May 2024 10:04) #31332

Let me ask all of you what compiler version do you use because not a single variant mentioned above works with latest version and switches /check or /undef. Some work with latest 9.02 if use nullify. But if i add nullify the variant conflicts with gfortran complaining that this is not a pointer. Without /debug and check the ones above work but what the point to use compiler without major checks ?

Another point is that unfortunately these 2D variants were not the ones which are needed to me. They were oversimplified and what actually needed is 3D or 4D or even more dimensional variants so the derived types will have 3-4 variables with 3-4 dimensions look like this

var1(idim1)%var2(idim2)%var3(idim3,idim4)

And here i fail completely...Both on FTN95 and Gfortran. Even without /debug /check

Hence because the problem could not be compiler-related i have to explain in detail where and how exactly i plan to use derived types. May be i am doing everything wrong from the start.

This is to model relativistic plasma but i will better explain that on similar example from real life. Suppose we investigate 4 species of fish. We divided aquarium on 100 levels of depth installed sensors in each level. On each fish we placed chip which controls them on 12 parameters. And we know exactly how many fish of each species is in each level of aquarium. So

dimension idim1 - idim1 = 4 species of fish dimension idim2 - Aquarium divided on idim2 levels of depth dimension idim3 - each fish is tracked by idim3=12 parameters (their temperature, oxygen content in blood, CO2 content etc) dimension idim4 - tells how many fish of each species is currently in each level of aquarium

When allocating arrays we need to deallocate all the data for each fish, allocate array again based on recent data obtained from the sensors and load this new data. Below we deallocate first, then allocate the data and test if we see on the water surface at least one fish (print) 😃

!2D sometimes works:                        ftn95 aaa.f95 /64 /link /debug  >z
!2D does not work without nullify:          ftn95 aaa.f95 /64 /link /debug /undef /check  >z
!3D below does not work even with this:     ftn95 aaa.f95 /64 /link /debug  >z
!
!               var1(idim1)%var2(idim2)%var3(idim3,idim4) 
!
!
module mod

type v3
  real,  allocatable, dimension(:,:) :: var3  ! idim3 and idim4. This  for just one level of aquarium, controls each fish by 12 parameters
end type v3

type v2
  type(v3), allocatable, dimension (:) :: var2 ! idim2 array contains variable  number of depth of aquarium
end type v2

type (v2) var1(0:3)  ! 4 types of fish will be controlled but generally could be arbitrary

Contains

integer function fun1 ()
do idim1 = 0, 3 
   idim2 = 100  
   idim3 = 12 
   CALL RANDOM_NUMBER(rand4)
   idim4 = rand4 *1000 + 1

    if ( allocated ( var1(idim1)%var2(idim2)%var3 )) deallocate ( var1(idim1)%var2(idim2)%var3 )
    allocate ( var1(idim1)%var2(idim2)%var3(idim3,idim4) )

    print *,'var1(',idim1,') var2(',idim2,') var3 (', idim3,'x',idim4,')'
    var1(idim1)%var2(1)%var3(1,1) = idim4
  
enddo  
fun1=2

end function fun1

end module mod
!=========================
Program Prg
use mod
integer, external :: fun2

jj = fun1 ()
jj = fun2 ()

        end program
!========================
integer function fun2 ()
use mod
  print*, var1(0)%var2(1)%var3(1,1) ! checking just one fish on the surface
fun2=2
end function fun2
4 May 2024 9:52 #31334

Dan, I used 9.02 without /check or /undef.

FTN95 gives, if I am not mistaken, an incorrect warning:

WARNING S:\LANG\dan.F90 12:  MOD!SPECIES is not ALLOCATABLE yet is used in an ALLOCATED test
5 May 2024 6:58 #31335

To previously test the program, I used PLATO (which was set to Gfortran !)

Now with /64 it crashes, but works with 32-bit

[FTN95/Win32 Ver. 9.00.0 Copyright (c) Silverfrost Ltd 1993-2023]

[Current options] DEBUG;ERROR_NUMBERS;IMPLICIT_NONE;INTL;LINK;LOGL;

    PROCESSING MODULE  [<MOD> FTN95/Win32 v9.00.0]
0004)   real, allocatable, dimension (:) :: var
WARNING - 1239: ALLOCATABLE components of a derived TYPE are not auotmatically 
    deallocated on RETURN from a subprogram
0014)   if ( allocated(species(i)%var )) deallocate (species(i)%var)
WARNING - 1179: MOD!SPECIES is not ALLOCATABLE yet is used in an ALLOCATED 
    test
        NO ERRORS, 2 WARNINGS  [<FUN1> FTN95 v9.00.0]
    NO ERRORS  [<MOD> FTN95 v9.00.0]
0031)    integer :: jj
WARNING - 242: Variable JJ has been given a value but never used
    NO ERRORS, 1 WARNING  [<PRG> FTN95 v9.00.0]
    NO ERRORS  [<FUN2> FTN95 v9.00.0]
Creating executable: prg.EXE
 Vern : FTN95 v9.00
 Opts : DEBUG;ECHO_OPTIONS;ERROR_NUMBERS;IMPLICIT_NONE;INTL;LINK;LOGL;
            0           0
            1           0
            2           0
            3           0
 species(           0) allocated with size            1
 species(           1) allocated with size            2
 species(           2) allocated with size            3
 species(           3) allocated with size            4
            0           1    0.785398    
            1           2     1.57080    
            2           3     2.35619    
            3           4     3.14159    

[FTN95/x64 Ver. 9.00.0 Copyright (c) Silverfrost Ltd 1993-2023]

[Current options] 64;DEBUG;ERROR_NUMBERS;IMPLICIT_NONE;INTL;LINK;LOGL;

    PROCESSING MODULE  [<MOD> FTN95/x64 v9.00.0]
0004)   real, allocatable, dimension (:) :: var
WARNING - 1239: ALLOCATABLE components of a derived TYPE are not auotmatically 
    deallocated on RETURN from a subprogram
0014)   if ( allocated(species(i)%var )) deallocate (species(i)%var)
WARNING - 1179: MOD!SPECIES is not ALLOCATABLE yet is used in an ALLOCATED 
    test
        NO ERRORS, 2 WARNINGS  [<FUN1> FTN95 v9.00.0]
    NO ERRORS  [<MOD> FTN95 v9.00.0]
0031)    integer :: jj
WARNING - 242: Variable JJ has been given a value but never used
    NO ERRORS, 1 WARNING  [<PRG> FTN95 v9.00.0]
    NO ERRORS  [<FUN2> FTN95 v9.00.0]
[SLINK64 v3.10, Copyright (c) Silverfrost Ltd. 2015-2023]
Loading C:\forum\mecej4\lgotemp@.obj
Creating executable file prg.exe
 Vern : FTN95 v9.00
 Opts : 64;DEBUG;ECHO_OPTIONS;ERROR_NUMBERS;IMPLICIT_NONE;INTL;LINK;LOGL;
            0           0
            1           0
            2           0
            3           0

( program crashes )

[FTN95/Win32 Ver. 9.00.0 Copyright (c) Silverfrost Ltd 1993-2023]

[Current options] DEBUG;ERROR_NUMBERS;IMPLICIT_NONE;INTL;LINK;LOGL;

(  this test continues to work with /32 /debug )
5 May 2024 2:29 (Edited: 20 May 2024 8:18) #31336

So do you find any problems in my setup of a bit more complex 4D derived type in previous post? It does not work at all

The reason why I use derived type is that it is impossible to allocate just one dimension of standard array of arbitrary size independent of other dimensions. Before i collected all data in the standard classical array like this

array (idim3,idim4,idim2,idim1)

where as i noted above idim1 was for 4 our different types of 'fish' - gold fish, shark, whale and say crab (where last two are not exactly a 'fish'). If number of fish of different types is very different (say, we track just one single piece of whale which is rare in the nature) then storing this way becomes inefficient because we allocate for whale same amount of storage as for other fish. Even more inefficient becomes storage when you realize that fish may gather just in some preferable layers of aquarium. If crab gather only on the bottom of it - we need to allocate huge number for idim4 (maximum allowed number of fish for specific layer) and keep that for all other layers and all kinds of fish because allocation of different idim4 for different layers (idim2) and different kinds of fish (idim1) is not allowed - all have to have the same idim4.

As a result if you control 1 billion of fish (particles - electrons, photons, ions and all sorts of compounds) with 12 parameters 4 bytes each you formally need not more than only 12e9*4 = 48 GB of RAM while with array like above you'll need sometimes a Terabyte size of mostly empty sparce array !!!

19 May 2024 1:36 (Edited: 19 May 2024 3:58) #31355

Quoted from DanRRight

if ( allocated ( var1(idim1)%var2(idim2)%var3 )) deallocate ( var1(idim1)%var2(idim2)%var3 )
allocate ( var1(idim1)%var2(idim2)%var3(idim3,idim4) )

Dan, I was reviewing this post. Where is var1(k)%var2(idim2) allocated ? I think your allocate only allocates var3(idim3,idim4)

You need to go through the tree allocating all var2, then all var3 arrays I think the following works on Ver 9.00.0

!2D sometimes works:                        ftn95 aaa.f95 /64 /link /debug  >z
!2D does not work without nullify:          ftn95 aaa.f95 /64 /link /debug /undef /check  >z
!3D below does not work even with this:     ftn95 aaa.f95 /64 /link /debug  >z
!
!               var1(idim1)%var2(idim2)%var3(idim3,idim4)
!
!
module modv3
  integer   :: idim1,idim2,idim3,idim4
  integer*8 :: bytes = 0
  type v3
    integer :: n
    real,  allocatable, dimension(:,:) :: var3  ! idim3 and idim4. This  for just one level of aquarium, controls each fish by 12 parameters
  end type v3

  type v2
    integer :: m
    type(v3), allocatable, dimension (:) :: var2 ! idim2 array contains variable  number of depth of aquarium
  end type v2

  type (v2) var1(0:3)  ! 4 types of fish will be controlled but generally could be arbitrary

Contains

integer function fun1 ()
  real    :: rand4
  integer :: k

  bytes = 0
  do idim1 = 0, 3
     idim2 = 100 + idim1*3
     idim3 = 12
     var1(idim1)%m = idim2
     allocate ( var1(idim1)%var2(idim2) )
     bytes = bytes + idim2*4

    do k = 1,idim2
      
      CALL RANDOM_NUMBER(rand4)
      idim4 = rand4 * 1000. + 1
  
      if ( allocated ( var1(idim1)%var2(k)%var3 )) deallocate ( var1(idim1)%var2(k)%var3 )
      allocate ( var1(idim1)%var2(k)%var3(idim3,idim4) )
  
      write (*,11) 'var1( ',idim1,' )% var2( ',k,' )% var3 (', idim3,' x ',idim4,' )'
   11 format ( a,i0,a,i0,a,i0,a,i0,a)

      var1(idim1)%var2(k)%var3(1,1) = idim4
      var1(idim1)%var2(k)%n         = idim4
      bytes = bytes + 4 + idim3*idim4*4
    end do
  end do 
  fun1=2

end function fun1

end module modv3
!=========================
Program Prg
  use modv3
    integer, external :: fun2
    integer :: jj

    jj = fun1 ()
    jj = fun2 ()

    write (*,*) '??'
    read (*,*) jj
end program
!========================
integer function fun2 ()
  use modv3
  integer :: j,k

  do j = 0,3
    idim2 = var1(j)%m
    do k = 1,idim2,4

      print*, var1(j)%m, j,k, var1(j)%var2(k)%n, var1(j)%var2(k)%var3(1,1) ! checking just one fish on the surface
    end do
  end do

  write (*,*) bytes,' bytes allocated'

  fun2=2
end function fun2

I'm not sure how much storage this requires ? (there is overhead for each allocatable components)

19 May 2024 3:30 #31356

Dan,

I have not used multi-level derrived types with allocatable components before. It certainly gives versatility of the data structure.

The de-allocate code in the example above is very under-done ! If you have allocatable components that need to be de-allocated then all their allocatable components must also be specifically deallocated first.

I left off the test if ( allocated ( var1(idim1)%var2 ) ) ... The required code would have to deallocate any %var3 allocated to %var2

19 May 2024 4:39 #31357

I have expanded to a smaller example to show deallocate of allocatable components, which appears to work.

!  ftn95 /64 /debug /link
!
!               var1(idim1)%var2(idim2)%var3(idim3,idim4)
!
!
module modv3
  integer   :: idim1,idim2,idim3,idim4
  integer*8 :: bytes = 0

  type v2
    integer :: n
    real,  allocatable, dimension(:,:) :: var3 
  end type v2

  type v1
    integer :: m
    type(v2), allocatable, dimension (:) :: var2 
  end type v1

  type (v1) var1(0:3)  ! 4 types of fish 

Contains

  integer function fun1 ()
   real    :: rand4
   integer :: k

    write (*,10) 
 10 format (/' regenerating data structure')
    bytes = 0
    do idim1 = 0, 3
       idim2 = 10 + idim1*3  ! was 100
       idim3 = 12
       if ( allocated ( var1(idim1)%var2 )) call deallocate_var2 ( idim1 )
       var1(idim1)%m = idim2
       allocate ( var1(idim1)%var2(idim2) )
       bytes = bytes + idim2*4

      do k = 1,idim2
        
        CALL RANDOM_NUMBER(rand4)
        idim4 = rand4 * 1000. + 1

        if ( allocated ( var1(idim1)%var2(k)%var3 )) then
          deallocate ( var1(idim1)%var2(k)%var3 )
          write (*,*) 'unexpected deallocate var1(idim1)%var2(k)%var3'
        end if
        allocate ( var1(idim1)%var2(k)%var3(idim3,idim4) )

        write (*,11) 'var1( ',idim1,' )% var2( ',k,' )% var3 (', idim3,' x ',idim4,' )'
     11 format ( a,i0,a,i0,a,i0,a,i0,a)

        var1(idim1)%var2(k)%n         = idim4
        var1(idim1)%var2(k)%var3(1,1) = idim4
        bytes = bytes + 4 + idim3*idim4*4
      end do
    end do 

    fun1=2
  end function fun1

  subroutine deallocate_var2 ( j )
   integer :: j,lj,k, nd

    if ( allocated ( var1(j)%var2 ) ) then
      nd = 0
      lj = var1(j)%m 
      do k = 1,lj
        if ( .not. allocated ( var1(j)%var2(k)%var3 )) cycle
        deallocate ( var1(j)%var2(k)%var3 )
        nd = nd+1
      end do
      deallocate ( var1(j)%var2 )
      nd = nd+1
      write (*,fmt='(a,i0,a,i0,a,i0)') '( var1( ',j,' )%var2( ',lj,' ) DEALLOCATED ',nd
    end if
  end subroutine deallocate_var2

end module modv3
!=========================
Program Prg
  use modv3
    integer, external :: fun2
    integer :: jj

    jj = fun1 ()
    jj = fun1 ()
    jj = fun2 ()

    write (*,*) '??'
    read (*,*) jj
end program
!========================
integer function fun2 ()
  use modv3
  integer :: j,lj,k

    do j = 0,3
      lj = var1(j)%m
      do k = 1,lj,4
        print*, var1(j)%m, j,k, var1(j)%var2(k)%n, var1(j)%var2(k)%var3(1,1) ! checking just one fish on the surface
      end do
    end do

    write (*,11) bytes,' bytes allocated'
 11 format (B'zzz,zzz,zzz,zz#',a)

    fun2=2
end function fun2

Paul, the following warning appears false. [FTN95/x64 Ver. 9.00.0 Copyright (c) Silverfrost Ltd 1993-2023] 0036) if ( allocated ( var1(idim1)%var2 )) call deallocate_var2 ( idim1 ) WARNING - 1179: MODV3!VAR1 is not ALLOCATABLE yet is used in an ALLOCATED test

20 May 2024 8:16 #31358

John, Will look at the idea to allocate separate subtypes but not sure right now how to start. So far i succeeded to make the last my example above (with multiple types) to work only when allocatable was just one variable out of 4, others were set in the source code as a constant values (integer parameters).

/* That allocatable variable was number of fish in the depth levels in the aquarium in the narrative i used above. This already saved me hundreds of GB. If i were able to add at least one more alocatable variable, say, the number of depth levels in the aquarium, all would be almost perfect.

Another method, very different from current one and requiring even more substantial rebuild, would be to use linked lists with pointers. Not sure how fast and optimized it is because definitely little who used that. Not sure how fast will be loading, saving and copying such data structures. Even with current method with types i got substantial speed reduction when just copied one array to another. If with usual arrays i was getting loading speeds 2.6 GB/second, just adding copying of that array to TYPEd array and one more simple operation reduced the total speed to 0.55GB/s. Standard hardware with PCIe 5.0 and latest MVNe allows potentially for 15 GB/s and is freely available even for pinguins in Antarctica

But decently, looks like single core programming is dead. All need to forget single cores and move to parallel programming. This compiler with debugger like SDBG and Plato allowing to debug parallel code would be killing software.

20 May 2024 9:24 #31359

Dan,

For derived types, I have a derived type of multiple allocatable arrays, and store their dimensions in the derived type. I then have an allocatable array of this derived type. In this way I don't include derived types in another derived type. I found this a very useful approach to shift my disk based database into memory. Derived types appear to be very robust, although I rarely re-allocate these data structures.

However, it appears that your multi-level derived type example appears to work ok in the revised code. It may work very well. Is it legal Fortran, as I don't know ?

As for your multi-thread comments, this is not plane sailing. I have been using OpenMP with some very good results for suitable calculations. I am achieving up to 100 GFLOPS performance, which impresses me, but that is with a well suited problem.

The problem I have is the overhead of starting an OpenMP mult-thread region is about 10 to 20 micro seconds, which is about 50,000 processor cycles. You can do a lot of calculation in 50,000 cycles, so small computation tasks can't use multi-threads in current OpenMP.

The other problem I have is when distributing threads across large sets of data is that the memory to cache transfer bandwidth demand is proportional to the thread count, but for cheap hardware, the memory transfer bandwidth does not scale up with core count. If you can keep your data in cache you get great results, but with gigabytes of data, threads often stall.

A good example of this is DOT_PRODUCT rarely suits multi-thread, although it is often used as a multi-thread coding example! Too small a vector, the start overhead defeats you, too large and the data is not in cache quick enough.

Who knows where these problems may be addressed, but probably not on my budget.

Please login to reply.