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

Casting a dynamic 1D array into a dynamic 2D array without copying data

vahid_a_1
Beginner
1,810 Views

Hi All,

I have the following problem. I want to cast a 1D array into column of 2D array in a loop. At 1st iteration the size of this 2D array is same as the 1D array. So. There should be no problem to cast it. At 2nd iteration, 1D array is going to have different elements. I want to cast it to 2nd column of 2D array.

This procedure continues till the norm of elements of 2D array is less than tolerance and it stops there. There,  I can not guess the number of columns of 2D array to allocate it before starting calculation...

here are three codes I have tried. None of them work for me :

program ptrtest

 real, pointer, CONTIGUOUS :: Mr(:)
 real, pointer, CONTIGUOUS :: Mp(:,:)
 real, DIMENSION(9) ::abc


 integer :: n = 2
 iter=3

 Do i=1,iter

 alpha2 = 2
 allocate(Mr(n**2))
 abc= 42

 Mr(1:n**2) = 0.5 * abc(1:n**2)
 write(*,*) 'Mr='
 write(*,555) Mr

 Mr(1:n**2) => Mp(1:n**2,1:1) 

 WRITE(*,*) 'Mp='
 WRITE(*,555) Mp

 end do

 555  FORMAT(F12.4,1X) 


 end program ptrtest

----------------------------------------------------------------------------------------------------

 

program ptrtest

 real, pointer, CONTIGUOUS :: Mr(:)
 real, pointer, CONTIGUOUS :: Mp(:,:)
 real, DIMENSION(9) ::abc


 integer :: n = 2
 iter=3

 Do i=1,iter

 alpha2 = 2
 allocate(Mr(n**2))
 abc= 42

 Mr(1:n**2) = 0.5 * abc(1:n**2)
 write(*,*) 'Mr='
 write(*,555) Mr

 do j = 1, iter
    Mp(:, j) = Mr
 end do

 WRITE(*,*) 'Mp='
 WRITE(*,555) Mp

 end do

 555  FORMAT(F12.4,1X) 


 end program ptrtest
 
----------------------------------------------------------------------------------------------------

program ptrtest
   
   real :: start, finish
   real, pointer :: Mr(:)
   real, pointer,CONTIGUOUS :: Mp(:,:)
   real, DIMENSION(4) ::abc

 
   integer :: n = 2
   
   
   call cpu_time(start)
   iter=2
   alpha2 = 2
   
   Do i=1,iter
   
   allocate(Mp(n**2,i))
   allocate(Mr(n**2))

   data abc/1,2,3,4/
   
   Mr(1:n**2) = 0.5 * abc(1:4)
   write(*,*) 'Mr='
   write(*,555) Mr
   

   Mp = TRANSFER (Mr,1.0)

      
   WRITE(*,*) 'Mp='
   WRITE(*,555) Mp
   
   end do
     
555 FORMAT(F12.4,1X)
   call cpu_time(finish)
   print '("Time = ",f10.7," seconds.")', finish-start
end program ptrtest

 

 

 

0 Kudos
4 Replies
mecej4
Honored Contributor III
1,810 Views

I have just skimmed your code, and it occurred to me that you should look at the RESHAPE intrinsic, see https://software.intel.com/en-us/node/526713 . Your code makes heavy use of pointer variables; you may be better off with allocated variables instead, except in a few special cases.

0 Kudos
vahid_a_1
Beginner
1,810 Views

Well, reshape can be another alternative method. Thanks for reminding. However, the main issue still remains unsolved.

I mean, How should I tell Fortran to cast the 1D array into the 2nd column of 2D array when second iteration starts. I need to have preserve and save the 1D arrays which are calculated at each iteration in the columns of 2D array.

 

I have tried the following test program for reshape and I recieved segmentation error when 2nd iteration starts :

 

program ptrtest
     real*8,  DIMENSION(8) :: a
     real*8,  DIMENSION(:,:), Allocatable :: b

     Do iter =1,3
     a = (/1,2,3,4,5,6,7,8/)
     b = reshape(a,(/iter,8/))
     PRINT*, 'SHAPE(a)=', SHAPE(a)
     PRINT*, 'SHAPE(b)=', SHAPE(b)
     
     WRITE(*,*) 'a='
     WRITE(*,100), a 
100  FORMAT(1X,F5.2)

     WRITE(*,*), 'b='
     WRITE(*,200), b 

     
     end do
      
200  FORMAT (1X,F5.3)  
end program ptrtest

 

RESULT:  

 SHAPE(a)=           8
 SHAPE(b)=           1           8
 a=
  1.00
  2.00
  3.00
  4.00
  5.00
  6.00
  7.00
  8.00
 b=
 1.000
 2.000
 3.000
 4.000
 5.000
 6.000
 7.000
 8.000

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
      2 [main] Reshape2 8200 cygwin_exception::open_stackdumpfile: Dumping stack trace to Reshape2.exe.stackdump

 

 

 

0 Kudos
JVanB
Valued Contributor II
1,810 Views

What you seem to be trying to do is just infeasible. The issue is that you want an array to grow dynamically, but the Fortran processor can use up memory just ahead of where the array lies in memory if you don't reserve that space in advance. The next growth step can't occur without overwriting memory that the Fortran processor owns or copying all your data over to a new area of memory that has enough space for the bigger array size.

But this is the kind of thing that has to be handled all the time in practice, so what does everybody else do about it? The problem of handling potentially massive amounts of data without knowing the size or even shape in advance is the subject of any data structures text. Fortunately, you don't need to read a whole book to address your problem, because one of the simplest data structures, a linked list, seems to be adequate for your purposes. First you define the type of a linked list node:

INTEGER, PARAMETER :: dp = kind(1.0d0)

TYPE Node
   REAL(dp), ALLOCATABLE :: Column(:)
   TYPE(Node), POINTER :: Next => NULL()
END TYPE Node

Then a pointer to the start of the linked list and the current node:

TYPE(Node), POINTER :: Head => NULL(), Current => NULL()

Then you can allocate the first node of the linked list:

ALLOCATE(Head)
Current => Head

Now you just work with the current node:

ALLOCATE(Current%Column(n))
Current%Column = [(i,i=1,n)]

And when you need another column, just allocate it and move on:

ALLOCATE(Current%Next)
Current => Current%Next

When you are done, you still have a pointer to the start of your data, so you can use it as it stands if that mode of access is sufficient, or you could allocate an array of the now known size and walk through the linked list and fill it with your data.

 

0 Kudos
mecej4
Honored Contributor III
1,810 Views

Perhaps you do not require using RESHAPE at all.

If you know the maximum number of iterations beforehand, simply declare B(1:8,IterMax), and within the loop set B(:,iter) = A.

If you do not, use an estimated upper bound of IterMax in the declaration and check for running into this limit in the loop.

If this is also impossible, you will need to rethink the goals and strategies. Note that RESHAPE does have optional arguments with which you can do padding.

0 Kudos
Reply