Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
what is the equivalent function of "i in range" used in python (creates a sequence of numbers between a and b), on Fortran?
Same for "append" (appends a passed object into the existing list)
How to create an array with some boxex that should not be full?
Thank you!
equivalent function of "i in range"
The implied do-loop is what you are looking for
(f(i), i=1, n)
Same for "append" (appends a passed obj into the existing list)
The list in python which can dynamically grow has no direct comparison in fortran.
As #IanBush has pointed out: There is an alternative using allocatable but note that it reallocates and copies the whole array every time
integer, allocatable :: arr(:)
arr = [1, 2]
arr = [arr, 3]
You might want to think about implementing your own derived type which can grow exponentially. Something similar to std::vector in c++.
How to creat an array with some boxex that should not be full?
Elaboration as given by a comment:
In this grid there are some black boxes that should not be filled and i dont know how to do this, there are also some boxes with two numbers and i dont know how to do this either.
You could just define boolean arrays for that (I assume you don't really care about memory consumption)
program main
implicit none
integer :: n, i, j
integer, allocatable :: grid(:,:,:)
logical, allocatable :: unused(:,:), double(:,:)
n = 10
allocate (grid(2,n,n))
allocate (unused(n,n), source=.true.)
allocate (double(n,n), source=.false.)
! set values
unused(1, 2) = .false.
do i = 1, n
do j = 1, n
if (unused(i,j)) cycle
if (double(i,j)) then
! use values grid(1,i,j), grid(2,i,j)
else
! only use value grid(1,i,j)
end if
end do
end do
end program
Related
This question already has answers here:
Multidimensional array with different lengths
(2 answers)
array of arrays in fortran
(2 answers)
Are there any problems with using jagged-arrays in Fortran with multiple levels of allocation?
(1 answer)
Closed 11 months ago.
I want to build up a number (N) of allocatable array but the total number of these arrays and the size of each array are not known beforehand. These information can only be read from the file.
Is there any way to read N and size of each array from the file; and then, build up such N allocatable arrays in Fortran code automatically?
Any suggestion/hint is appreciated.
You need a "jagged 2D array", something which Fortran does not support natively. Instead, you can build one yourself using a user-defined type which contains an array. For example,
module arrays
implicit none
type :: Array1D
integer, allocatable :: contents(:)
end type
type :: Array2D
type(Array1D), allocatable :: contents(:)
end type
end module
Then your program would look something like
type(Array2D) :: foo
integer :: N,M
integer :: i
! Read `N` from the file.
N = ...
allocate(foo%contents(N))
do i=1,N
! Read the size of the i'th array from the file.
M = ...
allocate(foo%contents(i)%contents(M))
! Read the i'th array from the file.
foo%contents(i)%contents = ...
enddo
I would like to access the the elements of an array in a an arrayed derived type using the subroutine sum_real. That is: sum over first entry in the weight for all people.
type my_type
real, dimension(:), allocatable :: weight
real :: total_weight
end type my_type
type (my_type), dimension (:), allocatable :: people
type (my_type) :: answer
allocate (people (2))
allocate (people (1)%weight(2))
allocate (people (2)%weight(2))
people (1) % weight(1) = 1
people (2) % weight(1) = 1
people (1) % weight(2) = 3
people (2) % weight(2) = 3
call sum_real ( people (:) % weight(1), answer % total_weight )
What I want to do is similar to the answer found in Array of derived type: select entry, except for the fact that I have an allocated array in an arrayed derived type instead of an single element.
But, I get a compiler error:
error #7828: The part-name to the right of a part-ref with nonzero rank has the ALLOCATABLE attribute (6.1.2). [WEIGHT]
What you try is not possible if your component is allocatable. The reference (6.1.2) is actually a reference to the official standard documents, which prohibits this.
The reason is simple, the allocatable components (scalar or arrays) are stored in a different part of memory than the derived type itself. Therefore if you write
sum(people%total_weight)
or
people%total_weight = 0
it is no problem, total_weight is not allocatable, it is stored within the derived type and the compiler just goes in a simple loop and sets one field after another to zero. You can know the address of each %totalweight beforehand.
On the other hand
sum(people%weight)
or
people%weight = 0
each %weight is stored elsewhere and you don't have any simple formula to compute where is each %weight(i).
The solution is either, to fix the size of the array, if possible
real, dimension(2) :: weight
or use a do loop
s = 0
do i = 1, size(people)
S = S + sum(people(i)%weight)
end do
If you have a F2003 compiler, and the bounds of the component array are the same for a particular parent array object, a third approach to the size specified by constant expression/use a do loop methods specified by VladimirF is to parameterize the type.
type my_type(n) ! This type has one parameter - n
integer, len :: n ! The parameter n is a length parameter.
real :: weight(n) ! This component depends on that parameter.
end type my_type
type (my_type(:)), dimension(:), allocatable :: people
! This integer is the size of the people component. Because
! people is allocatable it can be determined at runtime.
number_of_people = 2
! This integer is the size of the weight component that we want
! in the array people. Other arrays and scalars of type
! my_type can have different sizes for that component.
! Because people is allocatable this can be determined at
! runtime.
number_of_weights = 2
allocate( my_type(number_of_weights) :: people(number_of_people) )
! Define people%weight here.
people(1)%weight(1) = 1
...
! Using sum intrinsic for the sake of example
do i = 1, people%n
! The argument to sum is an array section.
print *, sum(people%weight(i))
! ^ ^ Reference to an element of a component
! | Reference to the entire people array
end do
Every element in an array of parameterized type has the same type parameters, hence every weight component in people has the same bounds, hence references such as people%weight become "regular".
Code using this approach (or the constant component size specification approach) still has to follow the restriction for component references that only one part of the reference can have non-zero rank (you can't work with people%weight as a whole as both people and the weight component have rank one).
In the allocatable component case some components in some elements might not be allocated and where they are allocated the component might have different bounds, making a "regular" reference to the data in the component across the elements of the array conceptually difficult.
I have an N-dimensional dataset (say real numbers) which is stored as a 1D array with an additional dimension array which specifies the original dimensions.
In addition, the functions to deduce the 1-D index from an N-D index and vice-versa are given.
I'm trying to figure out how do I make a do-loop (or equivalent) for the generic N-dimensional index (which will be transformed to 1D index of course) from some set of limiting lower indices to a set of upper indices.
So I need an "N-dimensional" loop which does not go over all of the values - only a portion of the array, therefore doing the linear index of an equivalent 1D array is not relevant (at least without modifications).
This is a schematic of my problem:
subroutine Test(Array,Dims,MinIndex,MaxIndex)
implicit none
real , dimension(1:), intent(inout) :: Array
integer, dimension(1:), intent(in) :: Dims,MinIndex,MaxIndex
integer, dimension(size(Dims)) :: CurrInd
integer :: 1Dindex
! size(Dims) can be 1, 2, 3 ,..., N
! size(MinIndex)==size(MaxIndex)==size(Dims)
! size(Array)==Product(Dims)
! 1Dindex=Get1dInd(NDindex,Dims)
! NDindex=GetNdInd(1Dindex,Dims)
! How do I actually preform this?
do CurrInd=MinIndex,MaxIndex
1Dindex=Get1dInd(CurrInd,Dims)
<Some operation>
enddo
end subroutine
I figured it is possible to loop over the Dims array and use an inner loop but I don't manage to write the procedure down properly.
Another option that didn't work for me (maybe because I use it incorrectly?) is FORALL, as that requires each index to be specified separately.
If you knew the dimensions of your arrays at compilation time you could do a series of nested DO loops, each of them running between pairs of components of MinIndex and MaxIndex. Since you don't know the dimensions, that's not possible.
The easiest strategy I can think of is to loop with a single DO loop over all the 1D indices. For each of them, compute the N-dimensional index, and check if it is within the bounds provided by MinIndex and MaxIndex: if it is, continue doing what you need; if it is not, discard that 1D index and go to the next one. If the indices are sequential you may be able to do something smarter that skips blocks of indices that you know you will not be interested in.
do OneDindex = 1, size(Array)
CurrInd = GetNDInd(OneDindex, Dims)
if ((any(CurrInd<MinIndex)) .or. (any(CurrInd>MaxIndex))) cycle
! <Some operation>
end do
Note that, as far as the index manipulation is concerned, this strategy is compatible with parallelising the loop.
Also note that Fortran variables must start with a letter: 1Dindex is not a valid Fortran variable name.
So this is the actual procedure I ended up with.
I have verified it and hope it will be useful to you as it was for me.
(I know this is not well commented, but the question has all the details and my time is extremely short at the moment)
Also, thanks ripero for helping out!
I decided not to use the CYCLE approach as I assume the code will work more efficiently when only the actual amount of loops are performed.
!-----------------------------------------------------------
subroutine Test(Array,Rank,Dims,InitInd,FinInd)
implicit none
real, dimension(1:), intent(inout) :: Array
integer, intent(in) :: Rank
integer, dimension(1:), intent(in) :: Dims
integer, dimension(1:), intent(in) :: InitInd,FinInd
!-----------------------------------------------------------
integer :: nOuter
integer :: i,j, OneDInd
integer, dimension(Rank) :: Curr
!-----------------------------------------------------------
! Check how many repetition for the outer-loop
Curr=FinInd-InitInd
nOuter=1
do i=2,Rank
nOuter=nOuter*(Curr(i)+1)
enddo
!-----------------------------------------------------------
! Actual looping:
Curr=InitInd
do j=1,nOuter
! Update minor indices (>1):
do i=1,Rank
if (Curr(i).GT.FinInd(i)) then
! Update next index:
Curr(i)=InitInd(i)
Curr(i+1)=Curr(i+1)+1
endif
enddo
! Loop over major index:
do i=InitInd(1),FinInd(1)
!OneDInd=Get1dInd(Curr,Dims)
!<operation>
! Advance major index:
Curr(1)=Curr(1)+1
enddo
enddo
end subroutine Test
I am given this code:
...
IMPLICIT REAL*8(a-h,o-z)
DIMENSION L1(L), L2(M), L3(N)
...
I want to use IMPLICIT NONE but I don't know how to declare variable type using DIMENSION and maintain one line declaration of L1 to L3.
Something like:
INTEGER, DIMENSION :: L1(L), L2(M), L3(N) !(this doesn't work)
The syntax for the dimension statement differs from that of specifying the dimension attribute in a declaration statement.
So, whereas
dimension i(4) ! Implicitly typed
gives i array nature of size 4,
integer, dimension(4) :: i
is the way to go.
Now to come to your question about declaring multiple arrays in one line:
integer i(4), j(5), k(6)
Finally, one can still use
integer, dimension(4) :: i, j(5), k(6), l
making i and l arrays of size 4 and j and k arrays of size 5 and 6.
Is there a way in Fortran to access many elements of an array without using a loop?
For example given array of 100 elements
real(100) :: a
can I do something like this to access elements 1,4,7,54,81 that do not follow a regular step?
a(1,4,7,54,81)= 3.21423
you could use a vector subscript: a( (/1,4,7,54,81/) )= 3.21423
As noted before, an array may be used as the indexes of an array. This is a so-called vector subscript.
A([1,4,7,54,81]) = 3.21423
sets the elements given to that value. (This is the same as the earlier answer but using the Fortran 2003+/modern array constructor notation.)
The array can be any rank-1 array, such as a variable or expression:
integer :: idx(5)=[1,4,7,54,81]
A(idx) = 3.21423
A(idx-1+1) = 3.21423
Of course, vector subscripts are of use in other settings, such as referencing:
print *, A(idx)
call sub(A(idx))
A(idx) = A(idx+1) + 5
However, array sections with vector subscripts are subject to various restrictions, such as:
not always may they be arguments to a procedure;
a pointer may not point to them;
not all such sections may be assigned to.
In the third case, if the same index appears more than once in the subscript we can't define it. So
print *, A([1,5,1])
is allowed, but
A([1,5,1]) = 3.
is not.
RESHAPE and WHERE are worth looking at.
If you are determining which elements to 'pull out' then maybe ALLOCATE a new variable and stuff the elements of A into B.
Maybe something like this:
REAL, DIMENSION(100) :: A
LOGICAL, DIMENSION(100) :: A_Mask
INTEGER :: SizeB
REAL, DIMENSION(:), ALLOCATABLE :: B
!...
A_Mask = .FALSE.
WHERE(A > 1.0)
A_Mask = .TRUE.
ENDWHERE
SizeB = SUM(A_Mask)
!... then allocate B and fill it.