How to Interchange dummy variables in Fortran 77? - fortran

Problem: I have an array which is created in the middle of a computation. I wanted to take back the information in this array to the main program and print it.
For example:
PROGRAM DRIVER
CHARACTER A(*)*(*),B(*)*(*)
CALL TEST1(A,B)
write(*,*) 'Print B ', B
END
SUBROUTINE TEST1(A,B)
CHARACTER A(*)*(*),B(*)*(*)
A(1)='APPLE'
A(2)='BAT'
B(1:2)=A(1:2)
END
In the above program, the array A is created in "SUBROUTINE TEST1" and I do not know the length of A. I wanted to bring back the information in 'A' through 'B' and print.
When I compile the above program, I am getting the following error.
gfortran -c -O4 -mcmodel=medium -fno-automatic -std=legacy -z muldefs -ff2c -frepack-arrays -fall-intrinsics Test.f
Test.f:2.24:
CHARACTER A(*)*(*),B(*)*(*)
1
Error: Assumed size array at (1) must be a dummy argument
Test.f:2.33:
CHARACTER A(*)*(*),B(*)*(*)
1
Error: Assumed size array at (1) must be a dummy argument
Test.f:6.29:
write(*,*) 'Print B ', B
1
Error: The upper bound in the last dimension must appear in the reference to the assumed size array 'b' at (1)
Test.f:6.72:
write(*,*) 'Print B ', B
1
Error: Data transfer element at (1) cannot be a full reference to an assumed-size array
make: *** [Test.o] Error 1

In C/C++ and Fortran you can pass `assumed size' arrays in and out of functions/subroutines. This is because arrays contain an address for a block of memory. The program then calculates a memory address for an element in this array using the starting address and the array index values. If you have a multi-dimensional array, you need to know how big the steps have to be for all but one of the dimensions. Imagine you have a 2D array. If you know that the x axis is 20 elements long, then y can be an undefined size, but you can always calculate a memory address for an (x,y) position. Address = 20 * y + x. As a general rule the slowest changing index is the one that can be an undefined size. In my example that's the y axis. In your code you're using arrays of character arrays. That means you've got 2 undefined dimension sizes. That's what the compiler error messages are referring to. If you define the size of the character arrays you should be able to get your code to compile.

Related

"In call to DSYEV, an array temporary was created for argument" in ifort but the related dimension is only 1

Related questions Temporary array creation and routine GEMM
Warning message (402) : An array temporary created for argument
For the following Fortran code (modified from dsyev in fortran 90)
program test_dsyev
implicit none
integer, parameter :: dp = selected_real_kind(15, 307)
real(dp), allocatable :: A(:,:), A2(:,:,:), work (:), w(:)
real(dp) :: c1
integer :: i, j
integer :: lwork, info, n, lda
character :: jobz, UPLO
n=5
allocate(A(n,n))
allocate(A2(1,n,n))
A = 0.0_dp
c1 = 1.0_dp
do i = 1, n
do j = 1, n
A(i, j) = i * c1 + j * c1
end do
end do
A2(1,:,:) = A
lda = n
lwork = 10 * n
jobz = 'N'
UPLO = 'U'
allocate(work(lwork))
allocate(w(n))
call dsyev(jobz,uplo,n,A,lda,w,work,lwork,info)
write (*,*) w
call dsyev(jobz,uplo,n,A2(1,:,:),lda,w,work,lwork,info)
write (*,*) w
end program test_dsyev
called d.f90.
ifort -mkl -warn all -check all d.f90 gives me
-1.58312395177700 -1.465651932086313E-015 8.229374109843719E-018
4.803282588162841E-016 31.5831239517770
forrtl: warning (406): fort: (1): In call to DSYEV, an array temporary was created for argument #4
Image PC Routine Line Source
a.out 0000000000408E86 Unknown Unknown Unknown
a.out 000000000040580B Unknown Unknown Unknown
a.out 0000000000403812 Unknown Unknown Unknown
libc-2.17.so 00002B10A2A31555 __libc_start_main Unknown Unknown
a.out 0000000000403729 Unknown Unknown Unknown
-1.58312395177700 -1.465651932086313E-015 8.229374109843719E-018
it seems the warning message is related to A2(1,:,:) and memory non-continuous. Yes, Fortran is column-major. But, the first dimension of A2 is 1. A2 should follow A2(1,1,1), A2(1,2,1),..., I mean, the first index of A2 does not play a role in memory allocation. Or am I totally wrong?
Let's consider a much simpler program to look at what's going on:
implicit none
integer i(1,1)
call s(i(1,:))
contains
subroutine s(j)
integer j(*)
end subroutine s
end program
Compiled with -check to enable temporary copying checks we can see exactly the same warning:
forrtl: warning (406): fort: (1): In call to S, an array temporary was created for argument #1
Like the example of the question, the dummy argument has assumed size and the actual argument is an array section of the same rank, but one rank smaller than the whole array.
The array section i(1,:) actual argument is contiguous, so perhaps there's no need for a temporary copy for the dummy j? Looking at this, ifort makes a temporary copy when i is not simply contiguous, even if it's "obviously" contiguous.1
However, because the dummy argument j is assumed-size, we don't need to worry about passing the array section i(1,:): we can pass the whole array i, or the simply contiguous section i(:,:). We can do this because the ranks of the actual and dummy arguments do not need to match when the dummy is assumed-size (or explicit-size).
Note that if the dummy is assumed-shape, then the ranks do need to match, but the compiler may handle the argument association by passing an array descriptor/dope instead of making a temporary copy: unlike assumed- and explicit-size array arguments, it's not necessary for an assumed-shape dummy to be contiguous. (The compiler may still make, and warn about making, a temporary copy when it decides that is beneficial, but it isn't always going to happen.)
Finally, I am speculating that the trigger for a warning is simple contiguity (happy for someone in the know to confirm/dispute), but there's some evidence that you can avoid the runtime check warning with a simple alternative approach as here. (It makes complete sense for the copy to be made if not simply contiguous: simple contiguity is defined in a way to be easy to check.)
1 i(1,:) is not simply contiguous, even when the first extent is 1, because of the rule of simple contiguity (F2018, 9.5.4):
no subscript-triplet is preceded by a section-subscript that is a subscript.
The : in second place is a subscript triplet, yet 1 in first place is a subscript.

FORTRAN subroutine thinks the length of a string I'm passing it is not what it is

stackoverflow. First-time poster, long-time reader. I am working on debugging a large program (that started in F77 but has evolved), and I'm getting a runtime error that the string I'm passing a subroutine is shorter than expected. The thing is, I'm putting in a debug statement right before calling the subroutine, and the string is indeed of the correct length. Can you help me figure this one out? Since the code is long I'll just post the relevant snippet of file her1pro.F here (note WORD="HUCKEL " with a space at the end, but this happens to all the strings):
SUBROUTINE PR1INT(WORD,WORK,LWORK,IORDER,NPQUAD,
& TRIANG,PROPRI,IPRINT)
...
CHARACTER WORD*7
...
WRITE(*,*)"LB debug, calling PR1IN1 from PR1INT"
WRITE(*,*)"LB debug, WORD=",WORD
WRITE(*,*)"LB debug, LENGTH(WORD)=",LEN(WORD)
CALL PR1IN1(WORK,KFREE,LFREE,WORK(KINTRP),WORK(KINTAD),
& WORK(KLBINT),WORD,IORDER,NPQUAD,TRIANG,
& PROPRI,IPRINT,DUMMY,NCOMP,TOFILE,'TRIANG',
& DOINT,WORK(KEXPVL),EXP1EL,DUMMY)
...
SUBROUTINE PR1IN1(WORK,KFREE,LFREE,INTREP,INTADR,LABINT,WORD,
& IORDER,NPQUAD,TRIANG,PROPRI,IPRINT,
& SINTMA,NCOMP,TOFILE,MTFORM,
& DOINT,EXPVAL,EXP1EL,DENMAT)
...
CHARACTER LABINT(*)*8, WORD*7, TABLE(NTABLE)*7, MTFORM*6,
& EFDIR*1, LABLOC*8
...
And this is the output I'm getting:
[xxx#yyy WORK_TEST ]$ ~/dalton/build/dalton.x
DALTON: default work memory size used. 64000000
Work memory size (LMWORK+2): 64000002 = 488.28 megabytes; node 0
0: Directories for basis set searches:
./:
LB debug, calling PR1IN1 from PR1INT
LB debug, WORD=HUCKEL
LB debug, LENGTH(WORD)= 7
At line 161 of file /p/home/lbelcher/dalton/DALTON/abacus/her1pro.F
Fortran runtime error: Actual string length is shorter than the declared one for dummy argument 'word' (6/7)
From the standard:
16.9.112 LEN (STRING [, KIND])
Description. Length of a character entity.
Class. Inquiry function.
Arguments.
STRING shall be of type character. If it is an unallocated allocatable variable or a pointer that is not associated, its length type parameter shall not be deferred.
KIND (optional) shall be a scalar integer constant expression.
Result Characteristics. Integer scalar. If KIND is present, the kind type parameter is that specified by the value of KIND; otherwise the kind type parameter is that of default integer type.
Result Value. The result has a value equal to the number of characters in STRING if it is scalar or in an element of STRING if it is an array.
Example. If C is declared by the statement
CHARACTER (11) C (100)
LEN (C) has the value 11.
16.9.113 LEN_TRIM (STRING [, KIND])
Description. Length without trailing blanks.
Class. Elemental function.
Arguments.
STRING shall be of type character.
KIND (optional) shall be a scalar integer constant expression.
Result Characteristics. Integer. If KIND is present, the kind type parameter is that specified by the value of KIND; otherwise the kind type parameter is that of default integer type.
Result Value. The result has a value equal to the number of characters remaining after any trailing blanks in STRING are removed. If the argument contains no nonblank characters, the result is zero.
Examples. LEN_TRIM (’ A B ’) has the value 4 and LEN_TRIM (’ ’) has the value 0.
I think the examples here tell the story.

Fortran code multidimensional array

I am converting an old fortran code to java but I am stuck with following line:
PARAMETER (MAXC=15)
REAL CKV(MAXC,MAXC)
DATA (CKV( 1,J),J= 2,15)/10*0.,.45,.02,.12,.08/
DATA (CKV( 2,J),J= 3,15)/ 9*0.,.45,.06,.15,.07/
Can someone explain the above last two lines.
Thanks
PARAMETER (MAXC=15)
This declares MAXC a parameter (constant) and assign the value 15.
REAL CKV(MAXC,MAXC)
This is a declaration of the floating point (single precision) array CKV of dimensions (MAXC,MAXC)
DATA (CKV( 1,J),J= 2,15)/10*0.,.45,.02,.12,.08/
DATA (CKV( 2,J),J= 3,15)/ 9*0.,.45,.06,.15,.07/
This statement assigns initial values to CKV (at least to some elements). 10*0. means "take 10 times the 0.".
To clarify my answer (as requested in the comment):
(CKV( 1,J),J= 2,15) means "initialize the array subsection CKV( 1,2:15)", i.e. 14 elements. This matches the 14 elements on the right-hand-side (10x0., .45,.02,.12,.08).
The second implicit loop starts at 3, so only 13 elements are assigned. Therefore, it is just 9*0..

How to run C codes in matlab

I want to run a c++ code in Matlab, in my code I have this
int max=(int)*mxGetPr(prhs[0]);
double a[max];
but when I use mex it has these errors
error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
'a' : unknown size
all for line 2, and I get errors for this file only , (I can mex example codes)
any idea how I can fix it?
The problem is that max is not a constant expression (or, at least, not marked as being constant). For the second line to work, you must have max being a constant, because the memory footprint of the array must be known prior execution (the array is allocated on the stack). If you do not know the size, you need to use something like
double *a = mxCalloc(max, sizeof(double));
Then you allocate a chunk of memory on the heap, which allows to use dynamic sizes.

Weird compilation error: catastrophic error: section length mismatch in array expression compilation aborted for shocktube.c

I am facing trouble in compiling a simple piece of code. Following are the details:
Variable declaration:
double q_old[3][N], q_new[3][N], u[3][N], flux[3][N+1], fl[3][N+1], fr[3][N+1];
The following line seems to be the source of error:
fl[0][1:N+1] = u[1][0:N]*u[0][0:N]; // this does not work
fl[0][1:N] = u[1][0:N]*u[0][0:N]; // this works
The error:
shocktube.c(47): catastrophic error: section length mismatch in array expression
compilation aborted for shocktube.c (code 1)
I am using intel icpc compiler. The first statement does not work but the second does, which is really weird because AFAIK the size of the LHS array in the first statement will be N(index varying from 1 to N) and size of RHS should also be N(0 to N-1), while in the second statement size of LHS is N-1.
Thanks,
The Intel array section notation is [start:length], not [start:end]. Therefore, this line
fl[0][1:N+1] = u[1][0:N]*u[0][0:N]; // this does not work
is invalid because you are indexing past the end of the array (specifically, you are asking for indices [1, N+2) in the fl array, whose last dimension only has N+1 elements).
The error probably should be a little gentler ("catastrophic" is not a term I'd apply to a user error), but this is ultimately not the compiler's fault.