Fortran Error # 6366: The shapes of the array expressions do not conform - arrays

I encountered this error message while compiling one of my Fortran codes. I found a few similar posts regarding the same error, but none of the situations in those posts apply to my case. I would appreciate any answer or help offered here. Thanks in advance!
(The code is really long, so I only cut out those sentences that are relevant.)
===================================================
DIMENSION A(20), COORDS(3)
REAL B, C, X, Y, Z
B = 1.0
X = COORDS(1)
Y = COORDS(2)
Z = COORDS(3)
DO I = 1,3
A(I) = COORDS(I)
END DO
C = SQRT ( X**2.0 + Y**2.0 ) + B
===================================================
The error message points to the last line:
error #6366: The shapes of the array expressions do not conform. [C]
If I comment out + B, then no error occurs.
I just don't get it. The elements of the array COORDS are passed on to scalar variables X, Y, Z. How come they and B (or C) are not conformable?
I know there must be something I don't quite understand about Fortran array. Please point out my mistake if you catch any.
Thanks a lot!
Justin

Is there a dimension statement elsewhere in the code for any of these variables? The error message seems to point to C; that commenting out +B eliminates the error seems to more solidly point to B.
This is why I like to have all characteristics of a variable declared on a single line.
e.g.,
real, dimension (20) :: a
instead of:
dimension A(20)
real A

Related

optimizing part of code with array constructor

The following simple example code gives correct results. However, I'd like to optimize it or make it more efficient. The constructor array, y, that I create in order to generate the position line spacing works, but it is very clumsy looking and inconvenient since the numbers in it are very specific. I want to make the numbers in the y array more general variables that depend on the earlier defined parameters in my code. Here is the code and then I'll be more clear:
PROGRAM TestRuns
IMPLICIT NONE
INTEGER :: i, j, k !matrix indices (i,j), spatial index k
INTEGER,PARAMETER :: n=5 !matrix size
REAL, PARAMETER :: a = -6, b =6 !end points of grid
REAL :: h !step size on position grid
REAL :: y(0:6) = (/(k, k=-6,6,2)/) ! generating spatial grid array
DOUBLE PRECISION :: M(n,n) !nxn matrix
h = (b-a)/(n+1)
DO i = 1,n
DO j = 1,n
IF (i .EQ. j) THEN
M(i,j) = y(i)**2
ELSE
M(i,j) = 0
END IF
END DO
END DO
END PROGRAM TestRuns
Instead of having
REAL :: y(0:6) = (/(k, k=-6,6,2)/) ! this line of code works but is not helpful in generalizing my code at all.
I really want to write something more general such as :
REAL :: y(0:n+1) = (/(k, k=a,b,h)/)
I always specify, a,b,n first in my code, so from these parameters I want to be able to then calculate h and the array y. I don't want to have to automatically put the values of array y in by hand as I'm doing now.
You'll have discovered that your compiler doesn't like the line
REAL :: y(0:n+1) = (/(k, k=a,b,h)/)
Change it to
REAL :: y(0:n+1) = [(k, k=INT(a),INT(b),2)]
that is, make the lower and upper bounds for k into integers. I doubt that you will ever be able to measure any increase in efficiency, but this change might appeal to your notions of nice-looking and convenient code.
You might also want to tweak the way you initialise M. I'd have written your two loops as
M = 0.0
DO i = 1,n
M(i,i) = y(i)**2
END DO
Overall, though, your question is a bit vague so I'm not sure how satisfactory this answer will be. If not enough, clarify your question some more.

How come these two matrices are not equivalent?

Assume we have a 3 dimensional array F and 2 dimensional matrix S.
First I find a matrix Y which is F multiplied by S. Then I try to find an estimate of F (lets call it F_est) from Y as sanity check in my code.
Can anyone see a flaw in logic, I dont seem to know why F_est is not exactly F.
F= randn(2,4,600);
S= randn(4,600);
for i =1:size(F,1);
for j=1:size(F,2)
for k= 1:size(F,3)
Y(i,k)= F(i,j,k) * S(j,k);
end
end
end
for i =1:size(F,1)
for j=1:size(F,2)
for k= 1:size(F,3)
F_est(i,j,k)= Y(i,k) / S(j,k);
end
end
end
then I try to see if F_est - F is zero and it is not. Any ideas. Much aprreciated.
**** EDIT after comments
Based on the answers I got I am wondering if the code below makes any sense?
for k=1:size(F,3)
Y(:,k) = squeeze(F(:,:,k)* S(:,k)
end
Am I able to recover F if I have Y and S?
When you create Y, you are replacing its values continuously. For any value of pair of i,k you are overwriting Y jtimes!
Those 2 codes are not equivalent, as F_est(i,j,k) computed only once, but you have Y(i,k) j times.
I don't know what you are trying to do, but a multiplication of a 3D matrix by a 2D matrix is not defined, and its not a 2D matrix

Fortran Array Splice Initialization

I'm trying to initialize an array with equal spacing between 0 and 1 in fortran.
My code is :
program test
double precision :: h
double precision, dimension(:), allocatable :: x
h = 1./11
if(.not. allocated(x)) allocate(x(10))
x(1:10) = [h:(1-h):h] (*)
end program
The error I am given is "The highest data type rank permitted is INTEGER(KIND=8)" at the stared line.
I've tried to change it with
x(1:10) = h:(1-h):h
x = h:(1-h):h
x(1:10) = (/(h:(1-h):h)/)
and various other forms with no luck.
The syntax you're using is not valid Fortran and implied DO loops can't have non-integer bounds. You want something like this:
x = h * real([(i,i=1,size(x))],kind(h))
For more information, look up "array constructors" in the standard or a textbook.
Don't use (1:10) on the left side - see https://software.intel.com/en-us/blogs/2008/03/31/doctor-it-hurts-when-i-do-this
This expression
[h:(1-h):h]
is, from a Fortran point of view, broken. It looks a bit like an array slice, but that would require integers, not reals, and ( and ) rather than the [ and ]. And it looks a bit like an array constructor, for which [ and ] are correct, but h:(1-h):h isn't.
Try this
x = REAL([(ix,ix=1,10)],real64)/11
(having declared ix to be an integer). The expression (ix,ix=1,10) is an implied do-loop and, inside the [ and ] produces an array with integers from 1 to 10. I trust the rest is obvious.
Incidentally, since the lhs of my suggested replacement is the whole of x you don't actually need to explicitly allocate it, Fortran will automatically do that for you. This is one of the differences between a whole array section, such as your x(1:10) and the whole array, x.
And if that doesn't produce the results you want let us know.

python - Matplotlib 3D input formatting Z (dependent) values

I have a question quite similar to this one Matplotlib 3D plot - 2D format for input data? but it only partly solved my problem (which was originally that .plot_surface() didn't recognize any arguments). What I am trying to do is plot a function of 2 parameters and this is what I have:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X,Y = np.meshgrid(positions[0],np.transpose(positions[1]))
Z = data[0]
Axes3D.plot_surface(X, Y, Z)
which throws this error:
TypeError: plot_surface() missing 1 required positional argument: 'Z'
data[0] is a 2D array. (data is a list of 2D arrays). positions is a tuple of a row vector and a column vector, so line 3 is essentially reconstructing positions as two row vectors and then making two matrices one for X and one for Y values as I believe Axes3D.plot_surface() requires.
My problem is that even though Z is 2D array, .plot_surface() refuses to recognize it as such.
Edit: I just confirmed that Z is indeed the correct shape using this:
if Z.shape == X.shape:
print('Same shape')
Axes3D.plot_surface(X, Y, Z)
So I have no idea why it will not work.
Even when I use X for Z like this (since it didn't complain about X missing or being the wrong shape) it still gets mad.
Axes3D.plot_surface(X, Y, X)
Edit: In looking around examples and trying things out, I finally got it to work. I hardly consider this solved though, because I still have no idea why one way works and another doesn't, and I don't want to leave this unsolved for posterity. I got it to work by doing this
surf = ax.plot_surface(X, Y, Z)
instead of "Axes3D.plotsurface()". I have no idea why this change got it to work, so please still help me figure this out.
As you said, it seems that the right way to do this is via axis object (ax in the code below):
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z)
Alternatively, you can still call it using Axes3D, but then you need to pass it the axis object ax, like so:
Axes3D.plot_surface(ax, X, Y, Z)

Fortran 77: How to use array output from function or subroutine

I've only been learning Fortran 77 (and its syntax) the last few days, and tried finding answers throughout the site and textbooks already and come up still confused, so I'd appreciate any help. I'm sorry if the formatting on this post is off; this is my first post, and I'm crunched for time.
I'm creating a program to multiply matrices. I want to create a subroutine or a function that will take two matrices as inputs (two 2x2 arrays), and return the multiplied matrix (one 2x2 array). I can't figure out how to get either a subroutine or a function to return an array of fixed size, or how to use the array once it's returned.
I tried using a function, which compiled on its own. But when I tried calling the function from my main program, I couldn't call it on its own:
MATMULT(MAT0, MAT0, MAT0)
1
Error: Unclassifiable statement at (1)
or assign it to another variable (I tried different REALs and arrays):
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Error: Return type mismatch of function 'matmult' at (1) (INTEGER(4)/REAL(4))
MATRIX1.f:26.22:
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Warning: Type mismatch in argument 'x' at (1); passed INTEGER(4) to REAL(4)
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Warning: Rank mismatch in argument 'x' at (1) (scalar and rank-2)
Since arrays are passed by reference, I'm really not sure what the function is returning, so how can I use the output matrix, if that is indeed the function's output?
I also tried using a subroutine, but (in addition to still not knowing what it's returning or where) then I get a "Two main PROGRAMs" error - so the compiler isn't differentiating between the main program and the subroutine. This might be a problem with my syntax on subroutines? I tried a few different things, but here's my most recent iteration of the code (I'm just trying to get the array-passing to work, so there's not actual matrix multiplication in here yet):
PROGRAM MATRIX1
INTEGER N
REAL A, B, MAT0(2,2), MATF(2,2), X(2,2), Y(2,2), Z(2,2)
REAL BLAH
PRINT *, " ENTER THE VALUE OF A: "
READ *, A
PRINT *, " ENTER THE VALUE OF B: "
READ *, B
PRINT *, " ENTER THE NUMBER OF MULTIPLICATIONS: "
READ *, N
C Creates the initial matrix
MAT0(1,1) = 1.0 - A
MAT0(1,2) = A
MAT0(2,1) = B
MAT0(2,2) = 1.0 - B
PRINT *, "M = ", MAT0
CALL MATMULT(MAT0, MAT0, MAT0)
PRINT *, "FINAL "
STOP
END PROGRAM
REAL SUBBROUTINE MATMULT(X, Y, Z)
END SUBROUTINE
Or (edited to add some of the recommended changes) with a function:
PROGRAM MATRIX1
INTEGER N
REAL A, B, MAT0(2,2), MATF(2,2), X(2,2), Y(2,2), Z(2,2)
REAL MATMULT(2,2)
PRINT *, " ENTER THE VALUE OF A: "
READ *, A
PRINT *, " ENTER THE VALUE OF B: "
READ *, B
PRINT *, " ENTER THE NUMBER OF MULTIPLICATIONS: "
READ *, N
C Creates the initial matrix
MAT0(1,1) = 1.0 - A
MAT0(1,2) = A
MAT0(2,1) = B
MAT0(2,2) = 1.0 - B
PRINT *, "M = ", MAT0
Z = MATMULT(X, Y)
STOP
END PROGRAM
FUNCTION MATMULT(X, Y)
REAL X(2,2), Y(2,2), Z(2,2), MATMULT(2,2)
RETURN
END
I'm still getting errors:
Z = MATMULT(X, Y)
1
Warning: Legacy Extension: REAL array index at (1)
MATRIX1.f:28.19:
Z = MATMULT(X, Y)
1
Error: Array index at (1) is an array of rank 2
In this era there is no reason for use FORTRAN 77. Fortran 90/95/2003 is easier to use, more powerful, and better assists the programer in finding mistakes. gfortran is an excellent open-source compiler.
Here is an example in Fortran 95 of a similar program/function: a function that implements a vector-cross product. The example shows the function and program in the same file (there are other approaches) with the function receiving two vectors and returning one vector. Example: Computing the cross product of two vectors in Fortran 90
You mention several problems in your question. Certainly your work will be enhanced using more recent Fortran dialects, as given in the answers by M. S. B. and Ilmirus. And you really should be using implicit none (even for Fortran 77 a lot of compilers support that - and lower case - as an extension).
Coming to the conceptual part, I must say that you need to continue your learning. However, if you want a function which returns the matrix product then you will have something like
function matmult(x, y)
real x(2,2), z(2,2), matmult(2,2)
... calculation of matmult
end function matmult
Followed by
z = matmult(x,y)
in the main program, where z is real z(2,2), rather than the scalar blah you have in your example, and is your result.
Coming to your subroutine, there are indeed problems: real subroutine matmult(x,y,z) requires not the real. Then calling this with call matmult(mat0, mat0, mat0) where you intend to update mat0 with a result is asking for aliasing problems. call matmult(x,y,z) will "store the result" where the subroutine calculations put it. Using intent as given by Ilmirus is a good guide to the behaviour desired by the programmer.
Finally, if you just want to get the result of multiplying A and B as matrices and storing in C: use C = matmul(A,B) with a later-than-F77 compiler.
However, in Fortran 77 one doesn't return array results, so the subroutine approach is the one to go for. In response to your edit:
REAL MATMULT(2,2)
is declaring matmult an array, not a function, so references to matmult(X,Y) give rise to your error.
There are two ways to do this:
1) Subroutine. Declare a subroutine like you did. However, specify input and output parameters:
REAL, INTENT(IN) :: X(2,2), Y(2,2)
REAL, INTENT(OUT) :: Z(2,2)
and call the subroutine using call keyword: CALL MATMULT
2) Function. Also specify input parameter, but now return value of the function:
! Insert calculation
MALMULT = ...
Don't forget to declare it in proper way: FUNCTION MATMULT(x,Y)
Call it: Z = MATMULT(X,Y)

Resources