In fortran, is it possible to index into elements of an array subject to an intrinsic? I am referring in particular to the transpose function. In the following code, I am generating and initializing an array named A and trying to index into a value inside the transposed array
program test
integer, dimension(5,3) :: A
integer :: i,j
A = reshape((/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15/), shape(A))
print *, transpose(A)(1,1)
end program test
however I am getting a syntax error as follows:
**D:\TEMP\FortranTest>gfortran -o Test Transposecommand.f90 Transposecommand.f90:11:22:
print *, transpose(A)(1,1)
1 Error: Syntax error in PRINT statement at (1)**
It there a way to accomplish this without having to declare a separate variable then assign the transposed array to it? I would like to avoid declaring new variables if possible...
No, Fortran doesn't support that kind of indexing into function results. You'll have to devise an elegant solution of your own (aka a kludge). My own would take account of
transpose(a)(i,j) == a(j,i)
Related
I have 2-dimensional array
real triangle(0:2, 0:1)
where "triangle" is an array of vectors (1-dim arrays)
also i have subroutine
subroutine vecSub(lhs, rhs, result)
real lhs(0:1), rhs(0:1), result(0:1)
result(0) = lhs(0) - rhs(0)
result(1) = lhs(1) - rhs(1)
return
end
is there any way to pass one of the vectors from "triangle" variable to this subroutine? Fortran-90 can do this: triangle(0, :) which gives first array of triangle, but i'm allowed to use only FORTRAN-77, so this won't do, any suggestions?
#Javier Martin wrote "not with the current layout of your array", but missed the opportunity to suggest an alternative.
If instead you declared the variable as follows:
real triangle(0:1, 0:2)
reversing the order of the bounds, you could then pass triangle(0,0), triangle(0,1) or triangle(0,2) to the subroutine and get exactly the behavior you want, due to a Fortran feature called "sequence association". When you pass a single array element to a dummy argument that is an array, you are implicitly passing that and following elements, in array element order. This is about the only allowed violation of the normal Fortran shape-matching rules, and was part of FORTRAN 77.
No, not with the current layout of your array, because of two reasons:
Fortran uses an array element order in which the leftmost dimension is contiguous. That is, in an array of size (n,m,l) the distance between elements (the stride) is (1,n,m), measured in units of array elements (that is, not bytes).
F77 does not include assumed-shape arrays a(:) which are generally implemented by passing a small descriptor structure that communicates details like the stride or the number of elements. Instead, you can only use assumed-length arrays a(*) which are normally a pointer to the first element, kind of like C arrays. You have to pass the length as a separate argument, and array elements have to be contiguous
This is the reason why you can "pass a subarray" to an F77 subroutine, as long as that subarray is e.g. a matrix column: elements therein are contiguous.
A possible solution (one that many current Fortran compilers implement) is that when you try to pass a non-contiguous subarray to a function that is not known to accept them, they make a copy of the array, and even write it back in memory if required. This would be equivalent to:
! Actual array
integer m(3,5)
integer dummy(5)
dummy = m(2,:)
call myF77sub(dummy, 5)
m(2,:) = dummy
However, as others are saying, you should try not to call F77 functions directly, but either adapt them to or at least wrap them in more recent Fortran interfaces. Then you can have code like the above in the wrapper, and call that wrapper "normally" from modern Fortran routines. Then you may eventually get around to rewriting the actual implementation in modern Fortran without affecting client code.
I am currently working on translating some legacy fortran code and I am having a hard time understanding a particular line in the code. The compiler also seems to find this line weird and throws out an error. From what I understand it is trying to initialize an array by sequencing 1 to 9 by increments of 1 and filling up the array matrix with this sequence in column major form.
program arrayProg
integer :: matrix(3,3), i , j !two dimensional real array
matrix = reshape((/1:9:1/), (/3,3/))
end program arrayProg
Is this syntax acceptable in fortran? (It has to be because it comes from the legacy code)
Am I misunderstanding what the line does?
The syntax is incorrect and such code cannot be compiled by a Fortran compiler, unless it implements some non-standard extension.
Intel Fortran accepts this:
A colon-separated triplet (instead of an implied-DO loop) to specify a range of values and a stride; for example, the following two array constructors are equivalent:
1 INTEGER D(3)
2 D = (/1:5:2/) ! Triplet form - also [1:5:2]
3 D = (/(I, I=1, 5, 2)/) ! implied-DO loop form
from Development Reference Guides:Array Constructors
(note: The links to Intel Documentation change frequently, if the link is dead, please notify me in the comment and try searching for "triplet form" and "array constructors")
To generate a sequence in a standard way one uses an implied do loop like
(/ (i, i=1,9) /)
the reshape then just changes the 1D array into a 2D one in column major order as you guessed.
I have a 4-dimensional array in Fortran called covi It is declared as:
real, dimension(10,10,2,2) :: covi
and computed in a certain way.
At some point, I need to take 2-dimensional slices of that array, lke for example covi(1,1,:,:), covi(3,4,:,:),covi(7,5,:,:), etc.
I have declared another variable real, dimension(2,2) :: cov and written cov=covi(7,5,:,:) but this is not working. It gives the following error message:
error #6366: The shapes of the array expressions do not conform. [COVI]
covi = cov(i1,i2,:,:)
In Matlab this notation works perfectly. It is pretty intuitive. How does one achieve this in Fortran?
Thanks
I have an original array called pres_lev3d, whose size is defined by pres_lev3d(im*jm, levsi), where im*jm is 72960 and levsi is 64. This corresponds to global atmospheric data, thus the size. The array is allocatable: real (kind=kind_io8), allocatable :: pres_lev3d(:, :). I have a second array, press_1d, whose size is also defined in a similar fashion pres_1d(im*jm, levsi), but in this array levsi is 1.
I need to concatenate both arrays (technically a 2d and 1d array) to an array of the shape (/72960, 65/). In MATLAB this seems like a very simple process, however, I can't seem to find an easy way to go around it in Fortran 90.
I have tried to create a third array
pres_lev=(/pres_lev3d, pres_1d/)
and also tried to use merge, but none of these approaches seem to work out.
I am fairly new to Fortran.
If I've followed your explanation correctly this would probably work
real(kind_io8), dimension(72960,65) :: out_array
...
out_array(:,1:64) = pres_lev3d
out_array(:,65) = pres_1d
If that's not easy enough, or if I've misunderstood your question, explain further. To allocate out_array to conform to your input arrays, try something like
real(kind_io8), dimension(:,:), allocatable :: out_array
...
allocate(out_array(size(pres_lev3d,1),size(pres_lev3d,2)+1))
...
out_array(:,1:64) = pres_lev3d
out_array(:,65) = pres_1d
Im trying to declare a type in my keyword argument of an array of Vectors that is variable dimensions choosen by the user at the start of the program. When I use a variable to declare the dimensions, terminal tells me the variable is unknown. This is not an issue in sub 0.4 Julia as multidimensional arrays can be declared with single dimensional arrays. Ive tried constants and they did not work for me either. Is there a way around this without dumping data to a text file and reading from function.
function dataDoer(len,preConns::Array{Array{Int64,1},(len)})
println("do stuff here")
end
function main()
local netDim = (2,2)
local preConns::Array{Array{Int64,1},length(netDim)} = fill!(Array(Array{Int64,1},netDim),Int64[])
dataDoer(length(netDim),preConns)
end
main()
ERROR: LoadError: UndefVarError: len not defined
You will have to make len a type parameter. (I've renamed it to N below, which is common practice for this kind of parameter.) Then you can do eg
function dataDoer{N}(preConns::Array{Array{Int64,1},N})
println("do stuff here")
end
Note that N is no longer an argument of the function, but is inferred from the type of preConns.
I would take a look at the docs for how Arrays are implemented, as they shed some light on what's going on here.
In Array{T,N}, the N doesn't refer to the length or size of an array, but it's dimension. Array can actually have variable length, with the option to push!, append!, and splice! elements in and out. To get the length of an array, you simply do length(A). Hope that helps clarify!