- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello, my problem is as follow:
I have an exemplary fortran class:
module mod_obj type object integer :: a, b, c real(kind = 8), allocatable, dimension(:,:) :: matrix contains procedure :: fun2 end type contains ! Initialize object subroutine fun1(obj, a, b, c) type(object), intent(out), allocatable, dimension(:) :: obj integer, intent(in) :: a, b, c integer :: s s = 10 allocate(obj(1)) allocate(obj(1) % matrix(s,s)) obj(1) % a = a obj(1) % b = b obj(1) % c = c ! do some more stuff e.g. calculate values of matrix end subroutine ! Perform some claculations depending on input argument(s) subroutine fun2(this, x) class(object) :: this integer, intent(in) :: x ! do some algebraic operation on matrix depending on x value e.g. matrix = matrix * x this % matrix = this % matrix * x end subroutine end module
From C/C++ I would like to:
- first call fun1 to initialize object (and save somehow its handle)
- call fun2 for different values of x to calculate new values of matrix in my saved object
If it simplify a little on C/C++ I do not need access to fields of Fortran object - actually I need only values of matrix which (in the worst case) I can copy in another Fortran function taking as an argument the pointer to C/C++ matrix.
Best,
Adam
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have not tried it, but I can imagine that the alternative way to call type-bound procedures will work from the C side:
call fun1( obj, a, b, c )
instead of: call obj%fun1( a, b, c )
You will have to have pointers to the Fortran object and I do not know for sure how the class(...) declaration interferes. In the worst case, you would need a small Fortran wrapper.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To call fun1, the C code would need to create, initialize and pass a "C descriptor" for an allocatable array of derived type. This is a F18 feature that ifort 16 and later supports. fun1 would also need to have bind(C) added.
fun2 cannot be called from C/C++ due to the CLASS object. You could create another routine, say, fun2C, that accepts it as type(object) and then passes it to fun2, but I would warn you that unless you really need CLASS there (your example does not), you will suffer a severe performance penalty passing a TYPE to a CLASS.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Kusiek, Adam wrote:.. From C/C++ I would like to:
- first call fun1 to initialize object (and save somehow its handle)
- call fun2 for different values of x to calculate new values of matrix in my saved object
If it simplify a little on C/C++ I do not need access to fields of Fortran object - actually I need only values of matrix which (in the worst case) I can copy in another Fortran function taking as an argument the pointer to C/C++ matrix. ..
@Kusiek, Adam,
See Quote #2 of this thread where the reverse of what is of interest to you is shown where a C++ class is created, consumed, and freed using procedures in Fortran:
https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/734563
You can apply the same concept the other way around with your Fortran "class" i.e., derived type and have suitable interoperable methods to use it from C++.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello, thank you for your all responses which are really helpful. In the meantime I have done sth like this:
module new_type public :: fun_dealloc, fun_alloc type subobj integer :: d integer :: g contains procedure :: setG end type type obj type(subobj) :: sub integer :: a,b,c real(kind = 8), allocatable, dimension(:) :: matrix end type contains function fun_dealloc(obj_c) result(status) bind(C, name = 'fun_dealloc') use iso_c_binding type(c_ptr), value :: obj_c type(obj), pointer :: obj_f integer :: status call c_f_pointer(obj_c, obj_f) if (allocated(obj_f % matrix)) then deallocate(obj_f % matrix) end if deallocate(obj_f) obj_f => NULL() obj_c = c_null_ptr status = 1 end function function fun_alloc() result(obj_c) bind(C, name = 'fun_alloc') use iso_c_binding type(c_ptr) :: obj_c type(obj), pointer :: obj_f allocate(obj_f) obj_f % a = 1 obj_f % b = 2 obj_f % c = 3 allocate(obj_f % matrix(20)) obj_f % matrix(10) = 4 call setG(obj_f % sub, 5, 6) obj_c = c_loc(obj_f) end function subroutine setG(this, x, y) class(subobj) :: this integer :: x, y this % d = x this % g = y end subroutine
and the C code:
extern "C" { void* fun_alloc(void); int fun_dealloc(void*); } int main() { void *p; p = fun_alloc(); int status = fun_dealloc(p); return 0; }
It looks it works but I the code efficiency is also very important to me.
@Steve - the example I gave before was simple - but it was rather just to show you the idea. In my problem I will need some more complex class with few allocatable matrices and subclasses. So do you think there is other way to solve this ? In fact what I need is just to keep handle to the object allocated in Fortran between successive calls of Fortran subroutines in C/C++.
Best,
Adam
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would use the F18 features for this, as I suggested above. You can even do the allocate and deallocate from C through the CFI_xxx calls declared in ISO_Fortran_binding.h. Construct the descriptor in the C code and pass it to Fortran code as needed.
If I have time this evening I'll turn your code into a worked example. But as I said above, this doesn't work for polymorphic objects and passing a non-poly to a CLASS() dummy will cause a lot of code to be executed on every call.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Steve
I will be really grateful for the working code using the proposed by you concept. I will also take a look at this today. I am using Intel Parallel Studio XE 2017 - so is this conecpt available in this version ?
And the last - what is the reason of overhead in the second example - I only pass pointer to address in memory between Fortran and C and make pointer association using c_f_pointer(). Is this overhead related to c_f_pointer ?
Best,
Adam
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
An interoperational issue you have is in Fortran, an allocatable array, or pointer to an array, has an array descriptor as opposed to C (for single dimensioned array) having a pointer to a scalar of the first element of the array, and then elsewhere a variable containing the count of elements. For pre-F18 you might consider declaring your object as:
module mod_obj use iso_c_binding type object integer(c_int) :: a, b, c, matrix_s integer(c_ptr) :: matrix_c real(kind = 8), allocatable, dimension(:,:) :: matrix contains procedure :: fun2 end type contains ! Initialize object subroutine fun1(obj, a, b, c) type(object), intent(out), allocatable, dimension(:) :: obj integer, intent(in) :: a, b, c integer :: s s = 10 allocate(obj(1)) allocate(obj(1) % matrix(s,s)) obj(1) % matrix_s = s obj(1) % matrix_c = c_loc(matrix(1,1)) obj(1) % a = a obj(1) % b = b obj(1) % c = c ! do some more stuff e.g. calculate values of matrix end subroutine ! Perform some claculations depending on input argument(s) subroutine fun2(this, x) class(object) :: this integer, intent(in) :: x ! do some algebraic operation on matrix depending on x value e.g. matrix = matrix * x this % matrix = this % matrix * x end subroutine end module =========== // C/C++ struct object { int a, b, c, matrix_s; double* matrix_c; // The Fortran array descriptor is hidden // objects are created and destroyed on the Fortran side };
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The overhead comes in when you pass a type(something) to a class(something). When a polymorphic object is received as an argument, it requires that the compiler pass a large data structure describing the class and its parent types, if any. A non-polymorphic object doesn't have this already made, so the compiler creates it on the stack for each call, and this is inefficient. Other implementations are possible, but that's the way it is now in ifort. If you're not calling it a lot, it may not matter, but there have been users here who were astounded how much faster their program ran when they replaced class by type in the dummy argument because they didn't need it to be polymorphic.
I'll work on your example.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I started working on this with the F18 feature, and realized that your type subobj has a type-bound procedure. That's not interoperable. The approach your current code takes, where you use a C_PTR, is probably best for now.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Steve for your effort. Since I still have some gaps in my knowledge and want to choose the most elegant and efficient way of implementation (and also close this subject) - so lets just summarize what was stated before:
1. From these two the faster is the second one (when I do not use polymorphism feature)
function fun_mat_slow(obj_f) result(status) class(obj) :: obj_f integer :: status, siz obj_f % matrix2(5) = 7 status = 1 end function function fun_mat_fast(obj_f) result(status) type(obj) :: obj_f integer :: status, siz obj_f % matrix2(5) = 7 status = 1 end function
2. When I would like to use C descriptor I can use it for these types with removed bounded procedures:
type subobj integer :: d integer :: g end type type obj type(subobj) :: sub integer :: a,b,c real(kind = 8), allocatable, dimension(:) :: matrix, matrix2 end type
What is then the benefit in efficiency of using C descriptor comparing to C_PTR?. As I have seen C-descriptor gives access to e.g. matrix both on Fortran and C. Does it also mean that when I have allocatable matrix I can initialize descriptor in C, allocate matrix on Fortran side and deallocate it on C side ?
3. Does the approach with C_PTR will have higher overhead than the approach with C descriptor ? (assuming I only want to store pointer to object created in Fortran and do not need to have access to its fields in C (the methods also do not have to be bounded in my case) - I do not use polymorphism)
4. Does C descriptor is available in Intel Fortran Studio XE 17 ?
Best, Adam
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
(1) The first case would be faster. The only reason to use class() for a dummy argument is if the procedure is going to do different things depending on the dynamic type.
(2) C descriptors are mainly for when the C code wants to do something with the Fortran object in a way not possible in Fortran 2008. Some examples are:
- Passing or receiving deferred-shape, allocatable or pointer arrays
- Accessing array bounds in C
- Passing a character value with length greater than 1 or character(*).
- Wanting to do allocation, deallocation or reshaping of a Fortran array in C code
- Using DIMENSION(..) assumed-rank
The F18 interoperability features were designed in part to help MPI with interfaces that could use the Fortran shape of the array, and in particular, assumed-rank.
(3) If you are just storing a pointer to the object, then by all means use C_PTR. But last night I realized there is a hitch - ifort may not let you DEALLOCATE a pointer that you reconstructed using C_F_POINTER because that loses the flag ifort uses to specify whether a pointer is allowed to be deallocated, even though, by the words of the standard, the deallocate is allowed. This is a flaw in the design and not easily worked around. What you may end up doing is doing the allocate/deallocate as malloc/free (in Fortran - ifort treats these as intrinsics), casting to a C_PTR with TRANSFER and then using C_F_POINTER. Ugly, I know.
(4) Yes. It was added in version 16.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page