Add element to FORTRAN pointer? - arrays

I have an array arr in fortran going from 1 to n where I need to test each element against the elements preceding and succeeding (i.e. i against i-1 and i+1) - the problem being elements 1 and n that have n or 1 as predecessor or successor, respectively (i.e. it loops).
Instead of testing the first and last elements separately, I'd rather run a loop like:
do i=1,n
call testi(i-1,i,i+1)
end do
and define a pointer (in order to not use a dummy array and twice the memory) like
arrpointer(0) => arr(n)
arrpointer(1:n) => arr(1:n)
arrpointer(n+1) => arr(1)
to "simulate" the loop in my array. (Note that each array element is a vector - arr(i)%vec(1:m) )
The above does not work as each new definition of the pointer will overwrite the previous. So the question arises:
Is there any way to actually add an element to a pointer array without deleting the previous definitions?
PS:
As current workaround, I use an allocatable type array with the pointers:
type :: pointerarray
real, pointer :: elementpointer(:)
end type pointerarray
type(pointerarray), allocatable :: arrpointer(:)
arrpointer(0)%elementpointer => arr(n)
do i=1,n
arrpointer(i)%elementpointer => arr(i)
end do
arrpointer(n+1)%elementpointer => arr(1)
while replacing the loop as below does not work:
arrpointer(1:n)%elementpointer => arr(1:n)
However there might be a simpler way of which I am not aware, as type arrays for the pointers again make the code not as nicely readable.

I don't think there's a way to do this with pointers the way you envision. Instead, I recommend using an integer array dimensioned 0:N+1 that map to the desired 1:N range. For example:
integer :: i(0:N+1), j
real :: a(N)
! -- Setup
do j=1,N
i(j) = j
enddo
i(0) = N
i(N+1) = 1
! -- Then you can do:
do j=1,N
! call mysub(a(i(j-1)), a(i(j)), a(i(j+1)))
enddo
Alternatively, you could use a function to define i(j).

I don't have Fortran on this machine so haven't tested this. It's also not entirely clear what OP's testi routine does. So, this is not a complete answer, but might provide some useful (or useless) hints at a pointerless solution.
Don't forget the intrinsic function chsift. One way to perform, say, a one-sided difference calculation on an array would be to write
arrdiff = arr - chsift(arr,1)
cshift shifts elements from one end of the array to the other unlike its cousin eoshift which performs an end-off shift. Of course chsift is likely to require the creation of a temporary of the same size as the array (in theory it could be done without a temporary, in practice it always seems to use one) so may be unappealing on performance and memory usage grounds.

Related

Remove all the rows after an index value from an array in Fortran

I want an array to remove all the rows after a certain index value from an array in Fortran. That means that if the size of the array initially is p, it should become q, where q is the index after which everything is to be removed.
Here is the relevant bit of code:
real(8), allocatable :: circlesx(:),circlesy(:)
allocate(circlesx(n**2-n))
allocate(circlesy(n**2-n))
do i=1,n-1
do j=i+1,n
call intersect2circles(stlo(i),stla(i),distance(i),stlo(j),stla(j),distance(j),ax,ay,bx,by,flag)
if (flag==0) then
circlesx(k)=ax
circlesy(k)=ay
circlesx(k+1)=bx
circlesy(k+1)=by
k=k+2
endif
enddo
enddo
The flag basically checks if two circles intersect or not. So if there is no intersection, no values are assigned to the arrays circlesx and circlesy. The size of the arrays which I am allocating at first is the maximum number of points of intersection of n circles = n^2-n. I get a segmentation fault if I don't allocate them.
Reshape also didn't work, although I might have done something wrong there. This gave an unclassifiable statement error:-
reshape(circlesx,[ n**2-n-1 ])
I want the size of the circles arrays to change to k-2 after the loops are done
So what I need is, if n=2, so circlesx and circlesy have a size of 2, then,
circlesx=[0,0]
.
.
some calculations
.
.
circlesx=[1.2,0] ! only one value has been allocated
.
.
reshape the array accordingly
.
.
circlesx=[1.2]
Is there any way to do this in Fortran? I am using an f90 file extension and using gfortran v7.3.0
Questions around here about dynamic resizing of an array generally care about enlargening the array. That is the harder problem.1
However, the fundamental considerations are much the same. Consider
integer, allocatable :: arr(:)
allocate(arr(3))
arr = [1, 2, 3]
end
With intrinsic assignment we see from elsewhere that we could just write
integer, allocatable :: arr(:)
arr = [1, 2, 3]
end
and have arr allocated to the correct shape as part of the assignment.
We've seen this to: enlarge an array
arr = [arr, 4]
remove "bad values":
arr = PACK(arr, arr>1.and.arr<4)
Selecting just the first few elements is as simple as
arr = arr(:q)
The days where compilers require special flags to compile such code correct are slowly passing, but do (especially if using an old version) check your compiler documentation for how to ensure automatic allocation happens on intrinsic assignment.
1 Even in the days without dynamic memory allocation, one handled "shorter" arrays simply. Take a static-sized array as large as you'll ever need and do some bookkeeping around how many elements are used. In modern code you may see such artefacts when using old libraries.

How to have a Function returning an array which starts at index 0

I have a function which returns an array:
PURE FUNCTION set_Xgrid() RESULT(x_grid)
REAL(dp), DIMENSION(:), ALLOCATABLE :: x_grid
INTEGER :: ii
ALLOCATE(x_grid(0:Nx-1))
DO ii=0,Nx-1
x_grid(ii) = x_o + ii*dx
END DO
END FUNCTION
I then just call this function like this:
REAL(dp), DIMENSION(:), ALLOCATABLE :: x
ALLOCATE(x(0:Nx-1))
x = set_Xgrid()
DO ii=0,Nx-1
PRINT '(I4,A10,F10.7)', ii, ", x(ii) = ", x(ii)
END DO
Output (first few lines):
0, x(ii) = 0.0000000
1, x(ii) = 0.0101010
2, x(ii) = 0.0202020
Even though the above code works as expected, I do not really understand how it works.
I thought the RESULT of a function was an implicit INTENT(OUT) and worked the same way: any value prior to the call of the function was ignored and the variable was automatically deallocated. If that is the case, the code somehow remembers that the variable x was initialized starting at index 0.
Is this the right way to have the returned array of a function start at index 0? Also, I'd like to understand what happens when a function returns an array.
There is not much point returning an array starting at a specific index. It is not important anyway:
x(3:5)
x = f()
will work for any function returning the array of the right size 3, even if it starts from 42 inside the function.
It definitely does not work as intent(out), allocatable argument. The values are just assigned to the right place of the array, counting from the array start, not using the actual indexes.
If the variable is not allocated at all prior the assignment
real, allocatable :: x(:)
x = f()
then it is allocated to start at 1 with the right size, again, where the result started inside the function does not matter.
Vladimir F's answer covers much of what you need to know. There is more detail to add, however.
It is important to repeat, first, that a function result is not at all like an intent(out) dummy variable. Except in cases that don't apply here the function result acts as an expression rather than a variable.
You ask
If that is the case, the code somehow remembers that the variable x was initialized starting at index 0.
This is a consequence of the rules of intrinsic assignment (see, for example, 7.2.1.3 of Fortran 2008). If the variable on the left of the assignment is an allocatable variable it may be deallocated first. This "may" is important: it isn't always deallocated.
If the variable array is deallocated then it will be reallocated with the bounds/shape of the expression on the right. The lower bound of the expression will be 1 regardless of the bounds of the function result.
However, in your case the shape of the variable array is the same as the shape of the expression. Here, the variable is not deallocated before it is reallocated. It thus keeps its original bounds (lower bound 0).

Pointer to subarray defined by a map

I want to define a pointer to a subarray. For a simple range this is easily done by pointer => array(i:j), but I can't figure out how to do this for a map like k=[k1,k2,k3]. If I would define another array I could use a loop like array2=[(array1(k(j)),j=1,size(k,1))]. But it isn't possible to assign a pointer in a similar way (pointer => [(array1(k(j)),j=1,size(k,1))]) since the r.h.s. of the expression seems to define another variabel which then not even has the target attribute. For simple tasks, a trick around this, is to first assign a pointer to the total array an to use the map on the readout. But in my case this doesn't seem to be possible.
I will attach to examples: The first one shows what I described above. The second one is a more complicated example, where the trick doesn't work anymore. And in addition a two dimensional map is required.
Minimal example:
program test
integer, parameter :: n=10,n_k=3
real,target :: a(1:n)
real :: b(1:n_k)
integer :: k(1:n_k)
integer :: j
real,pointer :: p(:)
! fill array a and define map k:
a=[(real(j),j=1,n)]
k=[((j+1)*2,j=1,n_k)]
! can be used to print the arrays:
!write(*,*) a
!write(*,*) k
! can be used to write only the part of a defined by k:
!write(*,*) (a(k(j)),j=1,n_k)
! this an similar things didn't work:
!p(1:n_k) => [(a(k(j)),j=1,n_k)]
! works, but not generally:
p => a
write(*,*) (p(k(j)),j=1,n_k)
! works, only for arrays:
b=(/(a(k(j)),j=1,n_k)/)
write(*,*) b
end program
More complicated (but also kind of minimal) example which shows (hopefully) the problem I really have. For an easy understanding some explanation leads through it. There are plenty of write commands to print the arrays. I appreciate for the amount of code, but I really don't see how to make a shorter and understandable working example:
module mod1
type base
real :: a
end type
type,extends(base) :: type1
end type
type,extends(base) :: type2
type(type1),allocatable :: b(:)
end type
type(type2),allocatable,target :: c(:)
contains
subroutine printer(z)
class(*),pointer,dimension(:) :: z
integer :: j,a_z,n_z
character(len=40) :: f,ff='(F10.2,1x))',form_z
! define format for printing:
a_z=lbound(z,1)
n_z=ubound(z,1)
write(f,'(I0)') (n_z-a_z+1)
form_z="("//trim(adjustl(f))//ff
! writing:
select type(z)
class is (base)
write(*,form_z) (z(j)%a,j=a_z,n_z)
end select
end subroutine
end module
program test
use mod1
integer,parameter :: n_b=8,n_c=6,n_js=3,n_ls=2
integer :: js(1:n_js),ls(1:n_ls)
integer :: j,l
class(*),pointer :: p(:)
character(len=40) :: f,ff='(F10.2,1x))',form_c,form_b
! define format for printing:
write(f,'(I0)') n_b
form_b="("//trim(adjustl(f))//ff
write(f,'(I0)') n_c
form_c="("//trim(adjustl(f))//ff
! creating and filling the arrays:
allocate(c(n_c))
c%a=[(2d0*real(j),j=1,n_c)]
do j=1,n_c
allocate(c(j)%b(n_b))
c(j)%b%a=[(real(l)*1d1**(j-1),l=1,n_b)]
end do
! write arrays to compare later:
write(*,form_c) c%a
write(*,*)
write(*,form_b) (c(j)%b%a,j=1,n_c)
write(*,*)
! denfining two maps (size and entries will be input in the final program):
js=[1,4,6]
ls=[2,7]
! using the maps to print only the desired entries:
write(*,*) (c(js(j))%a,j=1,n_js)
write(*,*)
write(*,*) ((c(js(j))%b(ls(l))%a,j=1,n_js),l=1,n_ls)
write(*,*)
! !!! here I want to use the maps as well, but so far I only know how to use ranges:
p => c(1:4)
call printer(p)
write(*,*)
p => c(2)%b(3:6)
call printer(p)
write(*,*)
end program
Edit:
Just for the record, I solved the problem now by using arrays of derived types including pointers and slightly changing the calling subroutines.
You cannot do this with pointer association (e.g. pointer1 => array1(vector_subscript). Section 7.2.2.2 of the Fortran 2008 standard that disallows this is:
R733 pointer-assignment-stmt is data-pointer-object [ (bounds-spec-list) ] => data-target
There are two other forms, but they do not match your use, nor would they change the outcome. Reading further:
R737 data-target is variable
C724 (R737) A variable shall have either the TARGET or POINTER attribute, and shall not be an array section with a vector subscript.
This is why you cannot perform the pointer association your are attempting. You can however work around this and with pointer allocation. See this code:
n_k = 3
k = [((j+1)*2,j=1,n_k)] ! a vector subscript
p => a(k) ! NOT OK. Violates C724
allocate(p(n_k)) ! Associate your pointer this way
p = a(k) ! This is OK.
write(*,*) p
Which yields (wrapped in your example program):
% ./ptrtest
4.00000000 6.00000000 8.00000000
This allocates p to be the proper size and then assigns from a with a vector subscript. This gets around the issue of directly associating p with a map of a. This snippet assumes the variables are declared and initialized per your example code. This shows that you can assign a vector subscript of an array to a pointer, but only one that is already associated, not during the association.
As noted in a comment to your Q, if you have a regular stride, you can make the pointer association directly. For your first test case, this would be equivalent and work:
p => a(4:2:8) ! Allocation to a strided array is allowed
If however, you have an irregular vector subscript then the method in this answer will be what you need to use to accomplish the pointer association.
Another workaround you can use is passing a pointer and the map to a procedure. Consider the following code:
program test
implicit none
integer, parameter :: nx = 10, nx_m = 3
integer,dimension(nx_m) :: x_map
integer :: i
real, dimension(nx),target :: a
real, dimension(:), pointer :: p
! initialize array
a = [(real(i*2),i=1,10)]
write (*,'(10(f5.1 x))') a
!define a map
x_map = [1, 9, 4]
! associate pointer
p => a
call print_map(p, x_map)
contains
subroutine print_map(apointer, map)
implicit none
real, dimension(:), pointer :: apointer
integer, dimension(:) :: map
write (*,*) apointer(map)
end subroutine print_map
end program test
In this case, p "knows" about a and the map of elements in a can be calculated in the caller. Rather than associating (=>) p as a map of a (which cannot be done), p is associated to a and the map passed along with it.
This code produces the output:
% ./ptrtest3
2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0
2.00000000 18.0000000 8.00000000

Fortran equivalent to matlab find - application to slicing matrix without memory duplication

I use the command find quite a lot in matlab, and I wonder how to translate this smartly in fortran to extract a slice of an array. In matlab you can slice with either logicals or indexes, but in fortran you need indexes to slice. I'm aware of the intrinsic subroutines pack et al, but have never used them. Also, since I'm dealing with big matrices, I would like to avoid duplicating memory. I want the sliced matrix to be manipulated within a subroutine. I've read somewhere that slices of array were not duplicated. I don't know how this the slicing in done in matlab though. I'm puzzled also because in matlab some allocations are transparent to you.
I'd like to know how to reproduce the examples below, and make sure I'm not duplicating stuff in memory and that it's actually elegant to do so. Otherwise, I would forget about slicing and just send the whole matrix(since it's by reference) and loop through an index array I...
Matlab example 1: simply reproducing find
v=[1 2 3 4];
I=find(v==3);
Matlab example 2:
m=rand(4,4);
bools=logical([ 1 0 0 1]);
I=find(bools==1);
% which I could also do like:
I=1:size(m,1);
I=I(bools);
for i=1:length(I)
% here dealing with m(I(i)),:) and do some computation
% etc.
Example 3: just call a subroutine on m(I,:) , but using directly booleans for slicing
foo( m(bools, :) , arg2, arg3 )
In advance thank you for your help!
Fortran doesn't have an exact match for Matlab's find but you can generally use either where or forall, and sometimes both, to replace its functionality.
For example, given an array v such as you have in your first example, the Fortran statement
where (v==3) do_stuff
will operate only on the elements of v which are equal to 3. This doesn't get you the indices of those elements as find does, but much of the use of find is for selecting elements for having stuff done to them, and in most of those cases the where construct is applicable.
Given v as before, and an index array ix which, in Fortran, is an array of logicals like this:
[.true., .false., .false., .true.]
you can use ix, so long as it is the same shape as v, in masked array assignments such as
where (ix) v = some_value
ix doesn't have to be an array of logicals, it can be an array of any type, if it were an array of reals you might have an expression such as
where (ix>=0.0) v = some_value
I don't think that any of the current Fortran compilers make copies of arrays to implement where constructs. I'll leave you to read about the forall construct.
Don't forget, either, that you can use arrays as indices for Fortran arrays, so the expression
v([1,3]) = 0
sets elements 1 and 3 of v to 0. You can, of course, use multiple array indices if your array has rank greater than 1.
When you start using this sort of indexing to pass non-contiguous sections of an array to a sub-program, then you have to start worrying about copying into temporary arrays (if that's the sort of thing that you want to worry about). I believe that compilers may make temporary copies if you do something like
call my_subroutine(array(1:12:3, 2:12:4))
to enable the subroutine, which does not know the indices of the elements of the array section at run-time, to operate on what it 'sees' as a contiguous array.
You can use "pack" with an implied do loop:
I = pack([(j,j=1,size(v))],v==3)
Bellow, in FORTRAN CODE, is an example of a subroutine that makes the equivalent of find in matlab or scilab. In the examples below, we want to (a) find the position of the vector where the vector is equal to 22 (b) find the positions of even numbers in a vector
PROGRAM Principal
REAL*8 A(8)
INTEGER n, npos, pos(8)
n=8
A = (/ 19, 20, 21, 22, 23, 24, 25, 26 /)
! Find the positions of vector A that is equal to 22
CALL FindInVector(n,A==22,npos,pos)
WRITE(*,*) pos(1:npos)
! Find the positions of vector A that contains even numbers
CALL FindInVector(n,ABS(A/2.d0-INT(A/2.d0))<1.d-2,npos,pos)
WRITE(*,*) pos(1:npos)
END PROGRAM Principal
!________________________________________________________________
! Subroutine that find positions of a vector of logicals TF (True or False). The first npos elements contains the response.
SUBROUTINE FindInVector(n,TF,npos,pos)
! Inlet variables
INTEGER,INTENT(IN):: n ! Dimension of logical vector
LOGICAL,INTENT(IN):: TF(n) ! Logical vector (True or False)
! Outlet variables
INTEGER npos ! number of "true" conditions
INTEGER pos(n) ! position of "true" conditions
! Internal variables
INTEGER i ! counter
INTEGER v(n) ! vector of all positions
pos = 0 ! Initialize pos
FORALL(i=1:n) v(i) = i ! Enumerate all positions
npos = COUNT(TF) ! Count the elements of TF that are .True.
pos(1:npos)= pack(v, TF) ! With Pack function, verify position of true conditions
ENDSUBROUTINE FindInVector
I think a simpler version is possible, see the subroutine below. The example shows how to find the values smaller than 0.1 in array x.
program test
real, dimension(:), allocatable :: x
integer, dimension(:), allocatable :: zeros
x=[1.,2.,3.,4.,0.,5.,6.,7.,0.,8.]
call find_in_array(x<0.01,zeros)
write(*,*)zeros
contains
subroutine find_in_array(TF,res)
! Dummy arguments
logical, dimension(:), intent(in) :: TF ! logical array
integer, dimension(:), allocatable, intent(out) :: res ! positions of true
! elements
! Local arrays
integer, dimension(:), allocatable :: pos
pos=[(i,i=1,size(TF))]
!pos=[1:size(TF)] ! valid on Intel compiler
res=pack(pos,TF)
end subroutine find_in_array
end program test

keeping array limits in fortran during subroutine call

I have the following program
module test
contains
subroutine foo()
integer, allocatable :: a(:)
allocate(a(-5:5))
call bar(a)
print *, a
end subroutine
subroutine bar(a)
integer, intent(out) :: a(:)
a = 0
a(-4) = 3 ! here
a(2) = 3
end subroutine
end module
program x
use test
call foo()
end program
In the line marked with "here" I am doing something wrong. The fact is that when I receive the array a (in the caller allocated from -5 to +5), the callee uses conventional numbering (1 to n), meaning that assigning -4 I am doing an out of boundary assignment. How can I instruct the compiler that, within the bar routine, the numbering of the a array must be the same as in the caller ?
The type of dummy argument that you are are using in the subroutine, with the dimension specified with a colon, is called "assumed shape". This name is the clue -- Fortran passes only the shape and not the lower and upper bounds. The lower bound is assumed to be one unless you override it as shown in the answer by kemiisto. If the lower bound is not fixed, you can pass an argument to use as the lower bound.
Later addition: a code example if the lower dimension isn't known at compile time:
subroutine example (low, array)
integer, intent (in) :: low
real, dimension (low:), intent (out) :: array
There are two common options:
As kemisto wrote, you pass a second argument. This was common in F77-style code. You can not use the LBOUND trick! It has to be passed as an integer.
You declare the argument to be a pointer, which includes the entire array descriptor. Then the bounds of the array in the subroutine are the same as in the calling scope. Of course you may lose on optimization this way.
How can I instruct the compiler that, within the bar routine, the numbering of the a array must be the same as in the caller ?
Not sure but according to the standard you can specify the lower bound for an assumed-shape array.
subroutine bar(a)
integer, intent(out) :: a(-5:)

Resources