Parameter corruption when interfacing FORTRAN lapack routine - fortran

I'm stucked with a heap corruption problem in Visual Studio 2008 with Intel Fortran Compiler 11. I'm working on Windows 7 64-bit.
This is a call to a (F77) lapack subroutine in my F90 program:
call dgetrs('N', nbParams, one, a, nbParams, ipv, x, nbParams, err)
Before this call the debugger shows expected values for all parameters. a and x stand for two "allocatable" variables with size (nbParams,nbParams) and (nbParams) respectively.
However, after running this line the execution stops with an Access violation reading location 0x0000000000000001. Since I have compiled lapack in debug mode I'm able to go inside the call, and I see that everything but 'TRANS' gets corrupted just in the first statement of DGETRS.
SUBROUTINE DGETRS( TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO )
...
CHARACTER TRANS
INTEGER INFO, LDA, LDB, N, NRHS
...
INTEGER IPIV( * )
DOUBLE PRECISION A( LDA, * ), B( LDB, * )
......
INFO = 0 **--> Now all input vars but TRANS are corrupted or dereferenced!**
I'm tried everything and I'm unable to locate the problem. Could anybody help me locating the problem?
Thanks for your help!

This kind of problems usually appear when using assumed shape arrays without an interface. Try declaring an interface such as:
INTERFACE
SUBROUTINE DGETRS( TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO )
CHARACTER TRANS
INTEGER INFO, LDA, LDB, N, NRHS
INTEGER IPIV( * )
DOUBLE PRECISION A( LDA, * ), B( LDB, * )
END SUBROUTINE
END INTERFACE

Related

Allocate multiple variables at once with SOURCE=

I am now trying to update my old Fortran code that includes the lines like (*)
allocate( a(2), b(2) )
a(:) = 0.0
b(:) = 0.0
Initially, I changed them to
allocate( a(2), source=0.0 )
allocate( b(2), source=0.0 )
but this is clearly not much simple. So I tried to combine them so that
allocate( a(2), b(2), source=0.0 ) !! (1)
I didn't expect it to work, but it actually worked for gfortran >=4.8 and Sun fortran 8.7 (while not for ifort-14). So I went through the ALLOCATE section of the F2003 and F2008 documents, and it seems that the restriction has been removed in F2008 that "If SOURCE= appears, allocation-list shall contain only one allocate-object". Does this mean that the above line 1 is no problem in F2008, and that the different behavior is simply due to different degree of F2008 support?
(*) In actual codes, I was trying to allocate several array components of a derived type, allocate( conf% crd(3,N), conf% vel(3,N), conf% frc(3,N), blah, blah,... ) while assigning zero to each of them. So I was wondering if it is possible to simplify those lines somewhat.
At the high level, yes, the restriction in Fortran 2003 that there is only one object in a sourced allocation is removed in Fortran 2008.
Now, on to other matters. First, you don't show the declarations of a and b. In a sourced allocation the objects to be allocated must be type compatible with the source. The simple case
real, allocatable, dimension(:) :: a, b
allocate( a(2), b(2) )
a(:) = 0.0
b(:) = 0.0
has the same Fortran 2008 effect as
real, allocatable, dimension(:) :: a, b
allocate( a(2), b(2), source=0.0 )
But what about
double precision, allocatable, dimension(:) :: a, b
allocate( a(2), b(2), source=0.0 )
?
And the second point from before is: Fortran 2008 is a relatively new thing. I don't trust all compilers to correctly implement the rules with multiple objects in a sourced allocation.

Eliminating hidden copies in Fortran

I wanted to ask some Fortran gurus about this issues I have with an up to date version of the Cray Compiler. I have several warnings that although they do not affect correctness, they will probably do for performance. The warning is:
This argument produces a copy in to a temporary variable.
Here is one of the situations where I get this warning. Within the same file (fem.f90) and module:
call fem( array_local( i, : ), pcor, arcol, inder, &
^
ftn-1438 crayftn: CAUTION FFEM, File = fem.f90, Line = 676, Column = 31
This argument produces a copy in to a temporary variable.
The routine FFEM from where array_local is called looks like:
--------------------------
subroutine ffem( alow, pcor, arcol, inder, iflag )
integer , intent( in ) :: alow(3), pcor(3)
real, intent( in ) :: inder,arcol
integer, intent( out ) :: iflag
integer:: array_local(5,3)
! within in a loop
call fem( array_local( i, : ), pcor, arcol, inder, &
..........
--------------------------
And here is fem subroutine:
--------------------------
subroutine fem (ac, pc, rc, id, flag )
integer, intent( in ) :: ac(3)
.......
--------------------------
I cannot find the way to get rid of that copy in which will definitely slow down my code. I was wondering, does anyone know why this happen, and how can I fix it?
If array_local must be defined as it is and you cannot define it as (5,3) as brady shows, you can consider an assumed shape dummy argument
subroutine fem (ac, pc, rc, id, flag )
integer, intent( in ) :: ac(:)
array passed there can be non-contiguous and still there is no copy, ac will be non-contiguous (strided) too.
You need explicit interfaces for that. That is best achieved by placing the subroutines in a module.
The feasibility of this change depends on your use of array_local elsewhere, but you could swap the order:
integer:: array_local(3,5)
and then call fem:
call fem( array_local( :, i ), pcor, arcol, inder, &
This will allow the compiler to simply send a reference to the appropriate part of the array_local array since columns are ordered contiguously in memory.

fortran dummy argument doesn't match actual argument. casting available?

I've recently inherited Fortran code that used to be built with an older version of the Intel Visual Fortran compiler. There's a section of code that used to compile, but now throws an error #6633 'The type of the actual argument differs from the type of the dummy argument.'
The problem is when a function called READ_AND_CONVERT is called with REAL*4 DATA_ARRAY(*), but in READ_AND_CONVERT that parameter is declared as INT*2. I think it really just wants the address of the DATA_ARRAY.
Is there a way to pass the address of the DATA_ARRAY, even though they're of different types?
Here is READ_AND_CONVERT:
SUBROUTINE READ_AND_CONVERT (MX, N)
C=======================================================================
C Reads Integer*2 Data Array and Converts it to Real*4.
C
C This is a service routine called by subroutines
C READ_XYZ_2, READ_XYZ_4, READ_XYZ_ALL and READ_XYZ_FULL
C=======================================================================
C
IMPLICIT NONE
C
INCLUDE 'XYZ.FOR'
INCLUDE 'COMMON_XYZIO.FOR'
INCLUDE 'COMMON_HDR.FOR'
C
C-----------------------------------------------------------------------
C Local Parameters
C-----------------------------------------------------------------------
C
LOGICAL BB_FOUND
INTEGER*2 MX, MY
INTEGER*4 N, J
REAL*4 YJ, BB
C
DIMENSION MX(*), MY(2)
EQUIVALENCE (YJ, MY(1))
C
C-----------------------------------------------------------------------
C
CALL GET_REAL_PARAMETER ('XYZ$_OFFSET', BB, BB_FOUND)
C
READ (LUGIN) (MX(J), J = 1,N)
C
IF (BB_FOUND) THEN
DO J = N, 1, -1
YJ = (SCALE_FACTOR * MX(J)) + BB
MX(2*J) = MY(2)
MX(2*J-1) = MY(1)
END DO
ELSE
DO J = N, 1, -1
YJ = SCALE_FACTOR * MX(J)
MX(2*J) = MY(2)
MX(2*J-1) = MY(1)
END DO
END IF
C
RETURN
END
Found a solution here:
Basically disable the warning... by setting Properties | Fortran | Diagnostics | Check Routine Interfaces [change from Yes to No]
The article also shows how to do casting, in their example of a complex array to a real array:
use ISO_C_BINDING
complex(8), allocatable :: c(:)
real(8), pointer:: p(:)
allocate(c(N))
call C_F_POINTER(C_LOC(c), p, [2*N])
call donothing(N, p)
There are directives in Intel Fortran which disable the argument type check for a given routine and for a given argument. To disable the checks for all your code is dangerous!
!DEC$ ATTRIBUTES NO_ARG_CHECK :: ARGUMENT_NAME
source: https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/288896

Passing an array from fortran to a C++ function

I have a main program in Fortran. I am using Intel Visual Fortran XE 2011 on Visual Studio 2010. I would like to use a function which is coded in C++. The function I'm using is getting several arrays (input - set from the main fortran program) and use them to form an output array (to be returned to the main fortran program).
I've taken the following steps:
1)I created a Fortran project with the Fortran main program and module and I set it as "startup project".
2)I created a C++ project of type "static library".
3)I added $(IFORT_COMPILERvv)\compiler\lib\ia32 as explained here http://software.intel.com/en-us/articles/configuring-visual-studio-for-mixed-language-applications
The C++ static library is build with no problem.
The errors I get is about the declaration of the real(8) variables in the fortran program.
I get the following two errors for all real(8) declarations, i.e. 6 errors in total:
error #5082: Syntax error, found '(' when expecting one of: :: %FILL , TYPE BYTE CHARACTER CLASS DOUBLE DOUBLECOMPLEX DOUBLEPRECISION ...
error #5082: Syntax error, found '::' when expecting one of: ( * , ; [ / = =>
Here is the code I used:
Main Fortran Program:
Program Fort_call_C
use iso_c_binding
implicit none
interface
subroutine vec_sum_c(a,b,c) bind (C, name = "vec_sum_c")
use iso_c_binding
implicit none
real(8) (c_double), intent (in), dimension (*) :: a,b
real(8) (c_double), intent (out), dimension (*) :: c
end subroutine get_filled_ar
end interface
integer:: i
integer (c_int)::m
real(8)(c_double),dimension(:):: a, b, c
open(unit=10, file="input_arrays.txt",status="unknown")
read(10,*) m
allocate(a(m),b(m),c(m))
do i=1,m
read(10,*)a(i),b(i)
end do
close(10)
call vec_sum_c(m,a,b,c)
do i=1,m
print*, c(i)
end do
pause
end program
And the C++ function is:
extern"C" void vec_sum_c(int *m, double *a, double *b, double *c){
int mm = *m;
for(int i=0;i<=m-1;i++){
c[i]=a[i]+b[i];
}
}
Could anybody please help me with this issue?
And would you please let me know if the idea of sending a whole array from a fortran program to a c++ routine is a safe or problematic (better-to-be-avoided) attempt?
Your Fortran syntax is out. You have the real kind twice. Try
REAL(C_DOUBLE), INTENT(IN), DIMENSION(*) :: a, b
etc.
C_DOUBLE is a named constant. It happens to have the value 8 with that processor.
Also:
you are missing the argument m in the Fortran interface body for the C function.
you change your mind about the name of the subroutine in the Fortran interface body between the opening and closing statement!
Your C++ for loop less than equal compares against m, that should probably be mm.
There are no inherent problem sending whole arrays in this manner.
I had only managed to pass the value of a varible from C
function to fortran function.
I have here pasted the two source files namely main.c and fortran.f
You can use these two files in microsoft visual studio 10. After
doing all the settings in visual studio as suggested in page http://software.intel.com/en-us/articles/configuring-visual-studio-for-mixed-language-applications, you need to make another change as;
go to the project property of C/C++ static library ;
go to C/C++
go to Code Generation
set the Runtime Library to Multi-threaded Debug (/MTd)
now you can build the program....
main.c:
#include <stdio.h>
#include <malloc.h>
void testc(double **pa, double **p)
{
double b;
double *a, *c;
int m;
c = (double*) malloc(sizeof(double));
*c = 10;
*p = c;
a = (double*) malloc(sizeof(double)*5);
a[0]=1.23;
a[1]=2.46;
a[2]=3.69;
a[3]=4.11;
a[4]=7.21;
*pa=a;
for (m=0;m<5;m++)
{
b=a[m];
b=b+1.0;
a[m]=b;
}
}
fortran.f:
program test
use iso_c_binding
implicit none
interface
subroutine testc(pa, m) bind(c)
use iso_c_binding
type(c_ptr):: m
type(c_ptr):: pa
end subroutine testc
end interface
type(c_ptr) :: pa
type(c_ptr) :: m
real(c_double),pointer::fpa(:)
real(c_double),pointer::fm(:)
call testc(pa,m)
call c_f_pointer(pa, fpa, [5])
call c_f_pointer(m, fm, [1])
print *, fm(1)
print*, fpa(1)
pause
end program test

DGEMM and Numerical Constants as Arguments

While using BLAS DGEMM matrix-multiply function, I noticed that for an uninitialized result matrix C, I get NaNs in the resultwhen I call it like so:
DGEMM('N', 'N', M, N, K, 1.0, A, LDA, B, LDB, 0.0, C, LDC)
However, if I declare ALPHA and BETA before-hand:
REAL*8 ALPHA, BETA
PARAMETER (ALPHA=1.0)
PARAMETER (BETA=0.0)
DGEMM('N', 'N', M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC)
then the multiplication works okay. Does anyone have any ideas as to why declaring the arguments works?
Note that I'm using the Intel Fortran compiler along with it's MKL library.
It would work if you passed alpha and beta as double precision numerical constants (eg, 1.d0), but you're passing it single precision constants, and Fortran 77 has no way of knowing dgemm's argument list and promoting the reals to double precision. (It might work with the single precision constants if you used MKL's Fortran 95 interface, but I'm not sure).
Because you're only passing pointers 4-byte arguments and the library subroutine is looking up 8-byte values, the rest of the calculation gets messed up.