Define array from a bigger one in Fortran - arrays

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

Related

What is wrong with array(2:)(::2) in fortran?

I am learning Fortran08 and am puzzled as to why I cannot execute the following
integer :: array(8)
READ(*, *) array
array(2:)(::2)
, but the following works fine
integer :: array(8)
integer :: temp(7)
READ(*, *) array
temp = array(2:)
temp(::2)
The answer is simple, but I don't know if that much useful. It simply is not legal Fortran syntax.
Why is it so? Because the standard says so. And why? Because the committee designed it that way. Why? You have to ask them, but note that there may be a clash with string array indexing.
Fortran simply does not use consecutive array indexing parentheses, unlike C. The array syntax of Fortran and C is very different in multiple aspects.
Doesn't array(2::2) achieve what you need?

Fortran 90 - Algebra operation with scalar and arrays

I am working with a Fortran 90 program that, amongst many others, has the following variables declared:
real(r8) :: smp_node_lf
real(r8), pointer :: sucsat(:,:)
real(r8), pointer :: h2osoi_vol(:,:)
real(r8), pointer :: watsat(:,:)
real(r8), pointer :: bsw(:,:)
And at some point in the program, there is an algebra operation that looks like this:
do j = 1,nlevgrnd
do c = 1,fn
...
smp_node_lf = -sucsat(c,j)*(h2osoi_vol(c,j)/watsat(c,j))**(-bsw(c,j))
...
end do
end do
I am trying to "translate" a dozen lines of this program to R, but the above excerpt in particular made me confused.
What is the dimension of smp_node_lf? Is it an scalar? Does it inherit the dimensions of the arrays sucsat,h2osoi_vol,watsat and bsw?
There is a lack of dimensions for smp_node_lf because it is a scalar, and it is receiving the value of that scalar operation multiple times, being rewritten, if there is nothing to save its value to a vector or something.
It will never inherit the dimensions of any of those elements, there is never a vector to be inherited, everything it is receiving is scalar
if you have to retrieve its value, assuming the original code is capable of it as it is, there should be another part inside this very loop that saves that value before it is overwritten by another pass.
If there is not such thing, implement it, you might be dealing with incomplete code that does nothing it was said to do.
I've dealt with my fair share of "perfect code" that "did miracles when I used last time" with not a single miracle to be found within its lines of code.

Possible to index into contents of array subject to transpose function?

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)

How to concatenate two arrays in Fortran 90

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

purpose to using allocatable without a deferred size or vice-versa

I'm in the process of learning fortran (90), with past experience in c and python. I'm reading about arrays (it's interesting to see that so much of the python array behavior is based on that of fortran); and I was wondering, is there ever a reason to assign an allocatable array without a deferred size? And is it possible to defer the size without using allocatable -- if so, how?
e.g.
REAL, DIMENSION(:) :: arr1
REAL, ALLOCATABLE, DIMENSION(20) :: arr2
Array terminology can be a bit daunting in Fortran. The first thing to realize is the difference between an actual argument, a variable for which a procedure has to allocate some memory, and a dummy argument, placeholders for actual arguments passed along by the calling procedure. If a variable is in a procedure's argument list, it is a dummy argument.
So, as for actual arguments, there are two kinds of arrays:
explicit-shape, e.g. <type> :: A(3,6)
deferred-shape, e.g. <type>, <allocatable|pointer> :: A(:,:,:)
A deferred shape must have an allocatable or pointer attribute.
When it comes to dummy arguments, there are also two kinds of arrays:
assumed-size, e.g. <type> :: A(4,5,*), B(1:2,4:*), C(m,n)
assumed-shape, e.g. <type> :: A(:,4:)
The actual and dummy arguments are not related in any way, so don't mix them. Also note that there exist something called automatic arrays, these look exactly like assumed-size arrays with dummy variables as sizes (C(m,n)), but don't appear in the argument list, so they are not dummy arguments.
For the assumed-size array, the last dimension's upper bound should be left unspecified (the *), other than that lower+upper bounds can be specified, including variables passed along to the procedure. Think of it as an array for which you re-specify the entire layout, irrespective of the actual argument. This allows you to do things like:
program toby
integer, parameter :: n = 10
real :: a(n**3)
call my_sub(a,n)
end program
subroutine my_sub(a,n)
integer, intent(in) :: n
real, intent(inout) :: a(n,n,*)
...
end subroutine
The other dummy argument, the assumed-shape, only allows you to specify lower bounds, as it gets its size info from the actual argument. This means you also can't redefine the dimensionality, and you need an explicit interface (e.g. via a module). This makes it more stringent, and also unnecessary to pass along size information with the array.
program toby
integer, parameter :: n = 10
real :: a(n,n,n)
call my_sub(a)
contains
subroutine my_sub(a)
real, intent(inout) :: a(:,:,:)
integer :: n
n = size(a,1)
...
end subroutine
end program
You can read about it in much more detail here I find it to be an ideal reference.
Last but not least, since you mention python, don't be to eager to apply python-like array slicing in Fortran, as it can cause the use of temporary arrays, which can slow down the program. You can use -fcheck=array-temps with gfortran to warn for that. Furthermore, even though elemental operations on whole arrays are recommended for efficiency (e.g. A=A+1 in using arrays efficiently), don't misinterpret that as "writing very concise code is good for efficiency". The latter is of course not (necessarily) true.

Resources