- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page