I am trying to visualize a 2D real array in fortran95 using opengl with intel parallel studio in msvs. For this I have found (trying to understand) fglDrawPixels on http://polarhome.com/service/man/?qf=fgldrawpixels&tf=2&of=IRIX&sf=3
In the explanation of the subroutine
SUBROUTINE fglDrawPixels( INTEGER*4 width,
INTEGER*4 height,
INTEGER*4 format,
INTEGER*4 type,
CHARACTER*8 pixels )
it says that pixels
Specifies a pointer to the pixel data.
I don't fully understand this, since the data I whant to show is real(4) (or GL_FLOAT) How do I declare a pointer that I can use??? (character*8 to a pointer to real(4) data) - I thought this would be declared as real(4), pointer, dimension(:,:) :: pixels but that does not seem to be what fglDrawPixels expects...
Any help or hint on this is much appreciated
That description of the routine's interface is incorrect. The pixels argument is of type integer(K_GLvoid), or in other words, an address-sized integer. It is NOT a Fortran pointer. Typically you would use LOC(buffer) here where buffer is whatever variable you're using to hold the pixel data. All these arguments are passed by value, and the calling convention is STDCALL.
If you are using Intel Visual Fortran, module IFOPNGL declares this with the correct interface.
Related
I am designing a module which works with the hdf5 Fortran library. This module contains subroutines to read and write arrays of different types and shapes to/from a file.
e.g. I wish to be able to call writeToHDF5(filepath, array) regardless of what the shape and type of array is. I realise that interfaces have to be used to achieve this with different types. I am however wondering if it is possible to have an assumed shape of the array.
e.g.
if an array was defined such as
integer(kind=4), dimension(*),intent(in) :: array
and a two dimensional array was passed this would work. Is there any way to do this without creating separate subroutines for each shape of the array?
As Vladimir F says, Fortran 2015 adds "assumed-rank" - this is useful Fortran-Fortran (it was requested by MPI for the Fortran bindings), but when you receive such an array, you can't do much with it directly without additional complications. Several compilers support this already, but few (if any?) support the newly added SELECT RANK construct that make this a bit more useful.
You can, however, use C_LOC and C_F_POINTER to "cast" the assumed-rank dummy to a pointer to an array of whatever rank you like, so that's a possibility.
The standard (even back to Fortran 90) does give you an out here. If you write:call writeToHDF5(filepath, array(1,1)) (assuming array is rank 2 here), the explicit interface of the called procedure can specify any rank for the dummy argument through the magic of "sequence association". There are some restrictions, though - in particular the array is not allowed to be assumed-shape or POINTER.
I know that this comes out late, but for any future readers - the answer is actually yes.
This is a simple example of a procedure to read a single data-set of integers with any given shape. The inputs needed were read from the HDF5 using a single routine which does not require any special specification and are the same for integer, real, string and so on.
I have tested it on a "0-D" array (so size of (/1/) ), 1-D, 2-D, 3-D and 4-D arrays.
In all cases, the data was retrieved properly.
(Note: I removed some checks regarding the Errorflag, as they are not critical for the example)
subroutine ReadSingleDataset_int(FileName,DataName,DataType,Data_dims,Errorflag,InputArray)
implicit none
character(len=*), intent(in) :: FileName,DataName
integer(HID_T), intent(in) :: DataType
integer(hsize_t), dimension(:), intent(in) :: Data_dims
logical, intent(out) :: ErrorFlag
integer, dimension(*), intent(inout) :: InputArray
integer :: hdferr
integer(HID_T) :: file_id,dset_id
ErrorFlag=.FALSE.
IF (.NOT.HDF5_initialized) THEN
CALL h5open_f(hdferr)
HDF5_initialized=.TRUE.
ENDIF
call h5fopen_f(trim(FileName),H5F_ACC_RDONLY_F, file_id, hdferr)
call h5dopen_f(file_id,trim(DataName),dset_id,hdferr)
call h5dread_f(dset_id,DataType,InputArray,Data_dims,hdferr)
call h5dclose_f(dset_id,hdferr)
call h5fclose_f(file_id,hdferr)
end subroutine ReadSingleDataset_int
My main interest in this now is - would it be possible to replace the type/class specific (integer/real/etc') with a generic one on the lines of:
class(*), dimension(*), intent(inout) :: InputArray
As I have several routines like that (for int, real, string) which only vary in that specification of the input type/class. If that limitation could be alleviated as well, that will be even more elegant.
(Just to point out the issue - the h5dread_f does not accept the buffer argument, InputArray in my case, to be unlimited polymorphic)
I have been trying to pass a character array from C++ to a Fortran subroutine but it seems like Fortran does not receive characters properly. I have been searching the web to find a solution but proposed ideas seem to be too complicated. An interesting (and concise) solution was proposed by Steve at Intel Fortran Forum but I cannot get it work in my code. So, I appreciate any suggestion to help me out to resolve this issue.
The following function is my C++ routine that makes call to fortran subroutines:
extern "C" void __stdcall F_VALIDATE_XML(const char* buffer, int len);
void CUDMEditorDoc::OnValidateXML()
{
CString fileName = "test.udm";
const char* buffer = fileName.GetBuffer();
int len = fileName.GetLength();
F_VALIDATE_XML(buffer, len);
}
And here is the Fortran subroutine that is supposed to receive character array:
subroutine validate_xml(file_name, len)
!DEC$ ATTRIBUTES DECORATE, STDCALL, ALIAS:"F_VALIDATE_XML" :: validate_xml
use xml_reader_structure
use, intrinsic :: ISO_C_Binding
integer(C_INT), value, intent(in) :: len
character(len, kind=C_CHAR), intent(in) :: file_name
integer :: i
i = 1
end subroutine validate_xml
In debug mode and when the program has stopped at line (i = 1), I hover mouse over file_name to see its contents but the Watch window says that it cannot find file_name symbol (although len is correctly passed). Also, if I watch file_name(1:8) in watch window, still I don't get the original character arrays. I believe there is something wrong with the way I pass parameters to Fortran but chances are Watch Window is not correct.
I appreciate any help that could shed some lights here.
Thanks
You fell into the trap which is caused by saying (even on Stack Overflow in heavily upvoted answers) that you should use ISO C binding to construct interoperable subroutines.
That is wrong, using the iso_c_binding module does not make the procedure interoperable and does not change the calling conventions.
The other, separate and equally important, feature in Fortran 2003 to C interoperability is the bind(C) attribute.
Notice, that Steve Lionel has it in the linked example. You should have
subroutine validate_xml(file_name, len) bind(C, name="F_VALIDATE_XML")
The bind(C) changes the calling conventions in several subtle ways and the largest difference is for character strings, which normally pass the length in a hidden argument, but not in interoperable procedures.
I'm having a problem of variables getting over-written for I don't know what reason. I've posted a chunk of the code below so you can see how things are declared. The variables strain,Qi,Qf,Qd,tel and Gc are passed into the subroutine and used to calculate ssgrad,strn0,strss0.
My problem is that tel and Gc are passed into the subroutine OK but are for some reason change value during this chunk of code.
Using print statements I've found that the problem first occurs during the 2nd do loop. When I set strss0 to 0, Gc and tel change value from both being equal to 1, to seemingly random numbers: tel=11.52822 Gc=-8.789086 (Just shown for the sake of example)
Each time I run the code they are set to the same values though.
Just to let you know, this subroutine interfaces with a commercial finite element package.
Many thanks in advance for any help with this
subroutine initcalcs(strain,Qi,Qf,Qd,tel,Gc,ssgrad,strn0,strss0)
implicit none
integer :: i,j
real*8:: nstrn0,nstrs0,strn0,strnf,varsq,normvar,lmbda0,lmbdaf,
# ssgrad,t0,tt,tel,nstrnf,nstrsf,Gc
real*8, dimension(3) :: strain,stran0,stranf,strss0,strssf,var
real*8, dimension(3,3) :: Qd,Qi,Qf
lmbda0=1.0d0
nstrn0=0.0d0
do i=1,3
stran0(i)=0.0d0
stran0(i)=strain(i)*lmbda0
nstrn0=nstrn0+stran0(i)**2
end do
nstrn0=dsqrt(nstrn0)
do i=1,3
strss0(i)=0.0d0
end do
In Fortran, there are two common causes of the corruption of memory values. One is a subscript error, where you assign to an array element using an incorrect subscript value. This writes to a memory location outside of the array. The other is a disagreement between the arguments in the call to a procedure (subroutine or function) and the dummy arguments of the procedure. Either can cause problems to appear at source code locations different from the actual cause. Suggestions: inspect your code for these problems. Turn on stringent warning and error checking options of your compiler. The use of Fortran >=90 and modules gives Fortran much better ability to automatically find argument consistency problems. You could monitor the memory locations with a debugger and see what it modifying it.
I concur with M. S. B.: turn on stringent warnings and error checking and verify the subroutine calls are passing arguments that have the same type and shape (array dimensions) as the subroutine expects.
The colons in the variable declaration syntax imply this is Fortran90 or later. If that's the case, I strongly suggest using the INTENT modifier to specify whether arguments are intended to be read-only.
For example, let's assume that of the arguments passed to this routine, strain, Qi, Qf, Qd, tel, and Gc are read-only input and the arguments are ssgrad, strn0, and strss0 are returned as output; that is, whatever value they have is overwritten by this routine.
The variable declarations for the arguments would change to:
real*8, dimension(3), intent(in) :: strain
real*8, dimension(3,3), intent(in) :: Qi, Qf, Qd
real*8, intent(in) :: tel, Gc
real*8, intent(out) :: strn0, ssgrad
real*8, dimension(3), intent(out) :: strss0
The INTENT keyword is an addition to Fortran 90 which allows the user to specify which arguments are read-only (INTENT(IN)), initialized but which may be modified within the routine (INTENT(INOUT)) and which are treated as uninitialized and will be set within the routine (INTENT(OUT)).
If INTENT is not specified, it is defaults to INOUT which is consistent with FORTRAN 77 (Note that there are minor differences between INTENT(INOUT) and INTENT not being specified but they aren't relevant in this example).
A good compiler will throw an error if a routine tries to assign a value to a variable declared INTENT(IN) and will at least throw a warning if a variable declared INTENT(OUT) doesn't get assigned a value.
If possible, set INTENT(IN) on all the variables which are supposed to be read-only. This may not be possible, depending on how those variables are passed to other routines. If INTENT isn't specified on arguments to routines called within this routine, it will default to INOUT. If you pass an INTENT(IN) variable as an INTENT(INOUT) argument, the compiler will throw an error. If this is happening in code you control, you have have to specify INTENT in a number of routines. This may or may not be desirable depending on whether you want to generally improve your code or just fix this one problem really quickly.
I'm assuming some of these variables are passed to external routines in the finite element package which I 'm guessing is linked to your code rather than compiled; I'm not sure how compile-time intent checking is handled in that case.
Say I have a bunch of variables a,b,c
integer*4 a
integer*8 b
real*8 c
is there a way to determine how many bytes these variables are using without calculating it manually. I have a long list of variables which I need to know the size of for write out purposes.
In Fortran 2008 the intrinsic function storage_size is the way to go. Also, c_sizeof is useful.
For integers in Fortran 95 you can use bit_size.
If you need to declare variables with specific storage size, use the kind constants from module iso_fortran_env like real32.
Of course, if you use the obsolete and nonstandard declarations as integer*4 or real*8 you always know the number of bytes. It is the number after the star (defined as the number of default characters that can be stored in the numeric type).
If you need size of some collection of the variables, you can make a derived type with the same components:
type,sequence :: dummy_t
integer*4 a
integer*8 b
real*8 c
end type
type(dummy_t) :: dummy
and use storage_size(dummy) or use the intrinsic constructor.
If you are using gfortran/ifort you can use the sizeof (gcc) /(IBM) command. Not sure about other compilers.
I am working with a legacy Fortran 77 code subroutine where the parameter types are not declared at the top of the code block.
Here is a snippet showing the very top of the subroutine.
SUBROUTINE BPASS(F1,F2,F3,F4,SI,N,A,IERR)
REAL * 4 A( N ),FV( 4 )
From the above, I think that A is an array of length N with type REAL *4, equivalent in size to a C float. Alternately, FV(4) is an array of length 4 with type REAL *4.
However, what are the types of F1,F2,F3,F4,SI,N,IERR, if the types are not listed? It appears that N should be an integer.
I need to know the types so that I can call the subroutine from C++ code. Is there a Fortran convention for the types that are not declared?
By default Fortran will assign the type integer to variables whose names begin with the letters I,J,K,L,M,N and type real to all other undeclared variables.
I agree with your parsing of the definitions of A and FV.
Modern Fortran provides the expression implicit none for ensuring that the default rules are not applied, but when working with old codes it's sometimes not possible to avoid familiarity with the old dark ways.
In FORTRAN77, by default variables starting with I, J, K, L, M, or N are INTEGER, otherwise they are REAL. FORTRAN90, and some variants of FORTRAN77, provide a mechanism to disable this by using IMPLICIT NONE.