hidden text to trigger early load of fonts ПродукцияПродукцияПродукцияПродукция Các sản phẩmCác sản phẩmCác sản phẩmCác sản phẩm المنتجاتالمنتجاتالمنتجاتالمنتجات מוצריםמוצריםמוצריםמוצרים
Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

A component cannot be an array if the encompassing structure is an array.

Julian_H_
Débutant
2 253 Visites

I have the following problem:

I need to create an datasets array which size is not known at first. It is an composition of different subarrays. 
For example the first subdataset has 4 elements, the second 10, and a third 8. Because this sizes are  not known at the start of the programm I can not do somethin like:

 

INTEGER(4), ALLOCATE :: datasets(:)

ALLOCATE(datasets(1:4+10+8))

The sizes of each subdataset is evaluated one after each other. Because there is no such thing like appending an array to an array I would have to reallocate the datasets size after each subdataset to manually expend the array. But this always involves a copy process which I definetly have to avoid.

So I tried to use an array of pointers in which every pointer points to an allocatable array. This works.

P1  | P2  | P3
1   |   2  |  3
1   |   2  |  3
1   |   2  |  3
1   |   2  |  3
    |   2  |  3
    |   2  |  3
    |   2  |  3
    |   2  |  3 
    |   2  |  
    |   2  |  

Its getting tricky now, because I have a subroutine  (sub1) which needs one array. Is there any possibility to pass the data inside the subroutine without copying it?

1  | 1  | 1  | 1  | 2  |  2  |  2  |  2  |  2  |  2  |  2  |  2  |  2  |  2  |  3  |  3  |  3  |  3  |  3  |  3  |  3  |  3  | 
MODULE TEST_MOD
	IMPLICIT NONE
	
	PRIVATE	
	
	! Type
	TYPE :: TYPE_TESTDATA
		INTEGER(4), ALLOCATABLE :: data(:)
	END TYPE TYPE_TESTDATA
		
	TYPE :: TYPE_TEST_PTR
		TYPE(TYPE_TESTDATA), POINTER :: p
	END TYPE TYPE_TEST_PTR
		
	CONTAINS
	
	! Subroutines
	SUBROUTINE sub1(array)
		IMPLICIT NONE
		INTEGER(4), ALLOCATABLE, INTENT(IN) :: array( : )
		
		! do smth with array
	
	END SUBROUTINE sub1
	
	
	SUBROUTINE sub2()
		IMPLICIT NONE
		
		INTEGER(4)							:: size_data1, size_data2, size_data3
		INTEGER(4)							:: num_datasets
		TYPE(TYPE_TEST_PTR), ALLOCATABLE	:: datasets(:)
		
		num_datasets = 3
		size_data1 = 4
		size_data2 = 10
		size_data3 = 8
		
		! allocate 
		ALLOCATE(datasets(1:num_datasets))
		ALLOCATE(datasets(1)%p%data(1:size_data1))
		ALLOCATE(datasets(2)%p%data(1:size_data2))
		ALLOCATE(datasets(3)%p%data(1:size_data3))
		
		datasets(1)%p%data = 1
		datasets(2)%p%data = 2
		datasets(3)%p%data = 3
		
		CALL sub1(datasets(:)%p%data)
	
	END SUBROUTINE sub2
END MODULE TEST_MOD

I hope I have described the problem quite understandably. Thanks for your help in advance.

0 Compliments
8 Réponses
FortranFan
Contributeur émérite III
2 253 Visites

Why can't you simply have an array of your first type, a container, that holds the data array?  Here's a simple example with floating-point data, it should give you the idea:

   type :: data_t
      real, allocatable :: data(:)
   end type

   type(data_t), allocatable :: datasets(:)
   integer :: i
   integer :: j

   allocate( datasets(3) )
   allocate( datasets(1)%data(4) )
   allocate( datasets(2)%data(10) )
   allocate( datasets(3)%data(8) )

   do i = 1, size(datasets)
      call sub( datasets(i)%data )
      print "(g0,i1,g0)", "datasets(",i,")%data = "
      do j = 1, size(datasets(i)%data)
         print *, datasets(i)%data(j)
      end do
   end do

contains

   subroutine sub( dat )

      real, intent(inout) :: dat(:)

      call random_number( dat )

   end subroutine

end
datasets(1)%data =
  0.282871902
  0.285217583
  0.948108971
  0.329367697
datasets(2)%data =
   7.51177669E-02
   4.24366593E-02
   3.02464366E-02
  0.472927332
  0.843287349
  0.165476203
   7.99026489E-02
  0.889786005
  0.139770269
  0.276428401
datasets(3)%data =
  0.226669431
  0.373131812
  0.915089190
  0.754180670
  0.162718296
  0.675101459
  0.131620944
  0.682734549

 

0 Compliments
Julian_H_
Débutant
2 253 Visites

Sure this is possible. But its no solving the actual problem. I need to pass the complete dataset not just a subdataset.

 

CALL sub1(datasets(:)%p%data)

not

CALL sub1(datasets(1)%p%data)

 

0 Compliments
andrew_4619
Contributeur émérite III
2 253 Visites

Julian H. wrote:
Sure this is possible. But its no solving the actual problem. I need to pass the complete dataset not just a subdataset.

CALL sub1(datasets(:)%p%data)

not

CALL sub1(datasets(1)%p%data)

i am really not sure what you are getting at here, if you are passing the whole dataset that would be:

CALL sub1(datasets)

you need to put the type declaration in a module so you can USE it in sub1 to declare the dummy arg being passed in.

 

0 Compliments
FortranFan
Contributeur émérite III
2 253 Visites

Julian H. wrote:

Sure this is possible. But its no solving the actual problem. I need to pass the complete dataset not just a subdataset. ..

You may want to consult some helpful references on Fortran: https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world

 

0 Compliments
Julian_H_
Débutant
2 253 Visites

andrew_4619 wrote:

Quote:

Julian H. wrote:
Sure this is possible. But its no solving the actual problem. I need to pass the complete dataset not just a subdataset.

 

CALL sub1(datasets(:)%p%data)

not

CALL sub1(datasets(1)%p%data)

 

i am really not sure what you are getting at here, if you are passing the whole dataset that would be:

CALL sub1(datasets)

you need to put the type declaration in a module so you can USE it in sub1 to declare the dummy arg being passed in.

 

yes correct. If i want to have this type in sub1. But i dont want because it makes the algorithm behind it much more complicated. What I need in in sub1 is an normal integer, allocatable array. So by passing the dataset inside I was talking about the data in general not the type datasets.

But what I have in sub2, which is the function collecting the data for sub1, is the shown type. Why am I using this type and not a normal integer array in sub2 I tried to explain in my initial post.

So I am looking for a solution to transfer the data into sub1 or how i can collect the data in sub2 in a different way, that i can just pass a normal integer array.

 

 

0 Compliments
andrew_4619
Contributeur émérite III
2 253 Visites

Well if you want a POD (plain old data) array in sub1 then go back to the old way of things and make data a large enough array and then as you populate it fill an index array  such that   ipos(i) the the start position of the i th sub array and its length is ipos(i+1)- ipos(i)  

0 Compliments
Julian_H_
Débutant
2 253 Visites

andrew_4619 wrote:

Well if you want a POD (plain old data) array in sub1 then go back to the old way of things and make data a large enough array and then as you populate it fill an index array  such that   ipos(i) the the start position of the i th sub array and its length is ipos(i+1)- ipos(i)  

I guess thats what I have to do if I am not able to change the algorithm. Thanks for your help.

0 Compliments
IanH
Contributeur émérite III
2 253 Visites

Perhaps also challenge the "definitely avoid" aspect of copying the array data.  Collect the data into an array of objects of type similar to your TYPE_TESTDATA type (or a linked list of similar objects), then flatten the data into a single allocatable array prior to calling the subroutine.

0 Compliments
Répondre