Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29004 Discussions

Fortran-Dynamic C Interface - PLEASE HELP!

bwilt
Beginner
925 Views

I have c libraries that unpack GRIB2 data that I receive from NCEP/NWS. The data looks correct INSIDE my c routines, but I am at a loss to accessing the c structure from fortran. The c library creates and dynamically allocates the a structure called 'gribfield' as follows:

struct

gribfield {

g2int version,discipline;

g2int *idsect;

g2int idsectlen;

unsigned char *local;

g2int locallen;

g2int ifldnum;

g2int griddef,ngrdpts;

g2int numoct_opt,interp_opt,num_opt;

g2int *list_opt;

g2int igdtnum,igdtlen;

g2int *igdtmpl;

g2int ipdtnum,ipdtlen;

g2int *ipdtmpl;

g2int num_coord;

g2float *coord_list;

g2int ndpts,idrtnum,idrtlen;

g2int *idrtmpl;

g2int unpacked;

g2int expanded;

g2int ibmap;

g2int *bmap;

g2float *fld;

};

typedef

struct gribfield gribfield;

The C routine I call simply returns a pointer to this structure as follows:

g2int g2_getfld(

unsigned char *cgrib,g2int ifldnum,g2int unpack,g2int expand,

gribfield **gfld)

I have tried everything trying to access this data from IVF 10.025 with no luck. My interface code is as follows:

interface

function g2_getfld (mgrib,ifldnum,unpack,expand,gfld)

!DEC$ ATTRIBUTES C, DECORATE, ALIAS:'g2_getfld' :: g2_getfld

integer (kind=int_ptr_kind()) gfld

type gribfield

sequence

integer*4 version

integer*4 discipline

integer*4, allocatable :: idsect(:)

integer*4 idsectlen

character, allocatable :: local(:)

integer*4 locallen

integer*4 ifldnum

integer*4 griddef,ngrdpts

integer*4 numoct_opt,interp_opt,num_opt

integer*4, allocatable :: list_opt(:)

integer*4 igdtnum,igdtlen

integer*4, allocatable :: igdtmpl(:)

integer*4 ipdtnum,ipdtlen

integer*4, allocatable :: ipdtmpl(:)

integer*4 num_coord

real, allocatable :: coord_list(:)

integer*4 ndpts,idrtnum,idrtlen

integer*4, allocatable :: idrtmpl(:)

integer*4 unpacked

integer*4 expanded

integer*4 ibmap

integer*4, allocatable :: bmap(:)

real, allocatable :: fld2(:)

end type

pointer (gfld, version)

character*1 mgrib(131040)

integer*4 ifldnum,unpack,expand

end function g2_getfld

end interface

How can I access the data from the gribfield structure in Fortran? For example, I want to print the parameter 'version'?

Thanks for any help you can provide!

Brett A. Wilt

0 Kudos
10 Replies
Jugoslav_Dujic
Valued Contributor II
925 Views
No, you cannot map a Fortran POINTER or ALLOCATABLE array to a C pointer. What you can do is use one of the following:

* Integer (or Cray) pointers on Fortran side, or, better
* ISO_C_BINDING module

The former is a non-standard (but common) extension. The latter is the new standard, so I recommend its use:

In short, each g2int* member will map to a TYPE(C_PTR) in Fortran. To dereference it into an array, you have to use a temporary POINTER array:
integer, pointer:: pidsect(:)
...
call C_F_POINTER(gfld%idsect, pidsect, (/idsectlen/) )
write(*,*) pidsect(1)
In the spirit of ISO_C_BINDING, you may also want to change !DEC$ATTRIBUTES into BIND(C, NAME="g2_getfld"). Don't forget to USE, INTRINSIC:: ISO_C_BINDING on the relevant places.

0 Kudos
bwilt
Beginner
925 Views

Thanks for the reply!

Do I use the type structure 'gribfield' in my fortran INTERFACE code to match the c structure? Is my code correct for this or do I not use the TYPE structure along with the allocatable array declarations?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
925 Views
Ah, I missed that.

INTERFACE is somewhat peculiar in Fortran, as the declaration of TYPE gribfiled will not be "visible" outside the INTERFACE (unless there's IMPORT statement supported in IVF10 -- I didn't check -- or the SEQUENCE attribute in both type definitions). Instead, it's best that you write it like this:

MODULE m_gribfield
USE, INTRINSIC:: ISO_C_BINDING
INTEGER, PARAMETER:: g2int =4
TYPE gribfield
 INTEGER(g2int):: version, discipline
 TYPE(C_PTR):: idsect
 INTEGER(g2int):: idsectlen
 ...
END TYPE gribfield
END MODULE m_gribfield
INTERFACE
 function g2_getfld (mgrib,ifldnum,unpack,expand,gfld) bind(C, NAME="g2_getfld")
 USE m_gribfield
 INTEGER(g2int):: g2_getfld
 INTEGER(g2int), VALUE:: ifldnum
 INTEGER(g2int), VALUE:: unpack
 INTEGER(g2int), VALUE:: expand
 TYPE(C_PTR):: gfld
 END FUNCTION
END INTERFACE
TYPE(g2_getfld), POINTER:: gfld
TYPE(C_PTR):: p_gfld
...
iret = g2_getfld(...p_gfld)
CALL C_F_POINTER(p_gfld, gfld)

I'm not positive what is mgrib/cgrib, so I left it untranslated -- you may wish to retain the character, or do it through type(C_PTR) as well.

0 Kudos
Steven_L_Intel1
Employee
925 Views
IMPORT is supported.
0 Kudos
bwilt
Beginner
925 Views

Ireally appreciate your time and help with this. I am notextensively familiar with c, so this is learning for me. Here is where I am now:

module m_gribfield

use, intrinsic:: iso_c_binding

integer, parameter:: g2int=4

type gribfield

integer(g2int):: version

integer(g2int):: discipline

type(c_ptr):: idsect

integer(g2int):: idsectlen

type(c_ptr):: local

integer(g2int):: locallen

integer(g2int):: ifldnum

integer(g2int):: griddef

integer(g2int):: ngrdpts

integer(g2int):: numoct_opt

integer(g2int):: interp_opt

integer(g2int):: num_opt

type(c_ptr):: list_opt

integer(g2int):: igdtnum

integer(g2int):: igdtlen

type(c_ptr):: igdtmpl

integer(g2int):: ipdtnum

integer(g 2int):: ipdtlen

type(c_ptr):: ipdtmpl

integer(g2int):: num_coord

type(c_ptr):: coord_list

integer(g2int):: ndpts

integer(g2int):: idrtnum

integer(g2int):: idrtlen

type(c_ptr):: idrtmpl

integer(g2int):: unpacked

integer(g2int):: expanded

integer(g2int):: ibmap

type(c_ptr):: bmap

type(c_ptr):: fld2

end type gribfield

end module m_gribfield

subroutine readgrib

use m_gribfield

use, intrinsic:: iso_c_binding

type

(g2_getfld), pointer:: gfld

type

(c_ptr):: p_gfld

interface

function g2_getfld (mgrib,ifldnum,unpack,expand,gfld)

!dec$ attributes c, decorate, alias:'g2_getfld' :: g2_getfld

use m_gribfield

character*1 mgrib(131040)

integer(g2int):: g2_getfld

integer(g2int), value:: ifldnum

integer(g2int), value:: unpack

integer(g2int), value:: expand

type(c_ptr):: gfld

end function g2_getfld

end interface

ierr=g2_getfld(%ref(mgrib),1,1,0,%ref(gfld))

call c_f_pointer(p_gfld, gfld)

print*,gfld%version

return

end

Here are my compiler error messages:

Error1 Error: This is not a derived type name. [G2_GETFLD]C:DevelopmentModel_x32_VS2005Sourcegribread.f1370

This occurs when the line

type(g2_getfld), pointer:: gfld

is added to the subroutione as indicated above.


Error2 Error: This variable or component must be of a derived or structure type [GFLD]C:DevelopmentModel_x32_VS2005Sourcegribread.f1476
Error3 Error: This is not a field name that is defined in the encompassing structure. [VERSION]C:DevelopmentModel_x32_VS2005Sourcegribread.f1476

These occur when I try and print the value of version with:

print*,gfld%version

Can you show me how to print the value of version? Is it incorrect above?

0 Kudos
g_f_thomas
Beginner
925 Views

What if you BIND(C,NAME="g2_getfld" )? but keep the !DEC$ meta command as it acts as a workaround for the compiler's failure to prepend a _ to the symbol.

Gerry

0 Kudos
Steven_L_Intel1
Employee
925 Views
Don't use that ATTRIBUTES line at the same time as BIND(C). At best you may get odd results, at worst a compile-time error (a future update will complain).
0 Kudos
Steven_L_Intel1
Employee
925 Views
First problem - the type you declared is gribfield, not m2_getfield. The other errors derive from that.

Your ATTRIBUTES line looks fine to me as it is.
0 Kudos
g_f_thomas
Beginner
925 Views

He could throw out the Alias and retain the Decorate and all would be fine unless Decorate's behavior changes in the future. Now you know why the HP guy suggestedthat one needs to experiment from release to release.

Gerry

0 Kudos
Steven_L_Intel1
Employee
925 Views
Gerry, you keep bringing up that HP article which was wrong. It is also not relevant here.
0 Kudos
Reply