Marshalling type to call fortran routine from C #

I am trying to call the FORTRAN77 routine from C # code using P / invoke - in case you are interested, I am trying to port some functions offered by the ARPACK library ( http://www.caam.rice.edu/software/ARPACK ). I have 2 questions.


First, I could not find clear instructions anywhere regarding sorting types in this context. More specifically, these are the types that are declared in my FORTRAN routine:

subroutine getEigenVectors & ( Matrix, n, which, nev, ncv, maxn, maxnev, maxncv, ldv, v, d) c %------------------% c | Scalar Arguments | c %------------------% character which*2 integer n, nev, maxn, maxnev, maxncv, ldv c %-----------------% c | Array Arguments | c %-----------------% c Real & Matrix(n,n), v(ldv,maxncv), d(maxncv,2) 

I found useful information here: What do I need for a character type marshal in Fortran? , from which I implied (maybe I'm mistaken) that I should use:

  • [MarshalAs(UnmanagedType.I4)] int pass integers
  • [MarshalAs(UnmanagedType.LPArray)] byte[] pass character strings

However, I do not know what to do with Real arrays. Does anyone have any ideas on this?


Secondly, I am confused by whether I should pass my arguments as a reference or not. I am by no means familiar with FORTRAN - I know that makes the task a bit complicated; however, only ARPACK does what I would like to do. I read somewhere, although FORTRAN routines accept all of their arguments as the default link. Should I pass all arguments as references?

Thanks in advance for your help! Guillaume


EDIT (8/6/11)

So here is my last take:

  [DllImport("Arpack.dll", EntryPoint = "#140")] private static extern void getEigenVectors( [MarshalAs(UnmanagedType.LPArray)] ref float[,] matrix, [MarshalAs(UnmanagedType.I4)] ref int n, [MarshalAs(UnmanagedType.LPArray)] ref byte[] which, [MarshalAs(UnmanagedType.I4)] int whichLength, [MarshalAs(UnmanagedType.I4)] ref int nev, [MarshalAs(UnmanagedType.I4)] ref int ncv, [MarshalAs(UnmanagedType.I4)] ref int maxn, [MarshalAs(UnmanagedType.I4)] ref int maxnev, [MarshalAs(UnmanagedType.I4)] ref int maxncv, [MarshalAs(UnmanagedType.I4)] ref int ldv, [MarshalAs(UnmanagedType.LPArray)] ref float[,] v, [MarshalAs(UnmanagedType.LPArray)] ref float[,] d ); 

A few things I have done here:

  • Skip int objects marked as UnmanagedType.I4 to match FORTRAN integer objects
  • Pass float[,] objects of size (m, n) and arrange as UnmanagedType.LPArray to match FORTRAN Real(n,m) objects Real(n,m)
  • Pass byte[] objects obtained using UnmanagedType.LPArray to match the FORTRAN Character*n objects. byte[] objects are computed as follows:

     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] which = encoding.GetBytes(myString); 
  • Pass an int BY VALUE object and sorted as UnmanagedType.I4 to indicate the length of the string. Note that I tried to put this argument right after the line, as well as at the end of the argument list.

This is my best shot - neither one nor the other that I tried worked. The method will be executed, however, it exits superfast (when it is assumed that it performs fairly complex calculations). Moreover, my 3 arrays are converted to strange one-dimensional arrays. Here is what the debugger debugs for me:

enter image description here

Any idea?

+2
source share
2 answers

I suggest you start with a little test code. Compile the FORTRAN.dll file with some routines with simple parameters and play with C # to make the call work. You can also wrap Fortran with many arguments in one structure (the TYPE keyword), which will greatly simplify the interaction.

Here is a working example that you can use to get a lot of ideas on how it works.

Original FORTRAN Code:

  SUBROUTINE CALC2(BLKL,BLKW, N_LAMINA,N_SLICE, LOAD, SLOP,SKW, & DIA1,DIA2, Y1, Y2, N1, N2, DROP1, DROP2, & PARRAY, P_MAX, P_MAX_INDEX, ENDEFCT) !DEC$ ATTRIBUTES DLLEXPORT :: CALC2 !DEC$ ATTRIBUTES ALIAS:'CALC2' :: CALC2 !DEC$ ATTRIBUTES VALUE :: BLKL, BLKW, N_LAMINA, N_SLICE, LOAD, SLOP, SKW !DEC$ ATTRIBUTES VALUE :: DIA1, DIA2, Y1, Y2, N1, N2 IMPLICIT NONE INTEGER*4, INTENT(IN) ::N_LAMINA, N_SLICE REAL*4, INTENT(IN) :: BLKL, BLKW, LOAD, SLOP, SKW, & DIA1, DIA2, Y1, Y2, N1, N2, & DROP1(MAX_LAMINA), DROP2(MAX_LAMINA) REAL*4, INTENT(OUT):: PARRAY(MAX_PATCH), P_MAX INTEGER*4, INTENT(OUT) :: P_MAX_INDEX, ENDEFCT INTEGER*4 :: NDIAG, N_PATCH REAL*4 :: SLNG, SWID REAL*4 :: DROPS_1(MAX_LAMINA), DROPS_2(MAX_LAMINA) ... END SUBROUTINE CALC2 

with different scalar and array values โ€‹โ€‹in real and integer form. For example, DROP1 introduces a 1D array. PARRAY outputs a 2D array as a 1D array. BLKL - input floats.

Pay attention to the decoration !DEC$ ATTRIBUTES VALUE , so as not to declare everything as a ref .

In C #, the code is called

  [DllImport("mathlib.dll")] static extern void CALC2(float major_dim, float minor_dim, int N_lamina, int N_slices, float total_load, float slope, float skew, float diameter_1, float diameter_2, float youngs_1, float youngs_2, float nu_1, float nu_2, float[] drops_1, float[] drops_2, float[] pressures, ref float p_max, ref int p_max_index, ref EndEffect end_effect); ... { float max_pressure = 0; int max_pressure_index = 0; float[] pressures = new float[Definition.MAX_PATCH]; EndEffect end_effect = EndEffect.NO; CALC2(length, width, lamina_count, slice_count, load, slope, skew, dia_1, dia_2, y_1, y_2, n_1, n_2, drops_1, drops_2, pressures, ref max_pressure, ref max_pressure_index, ref end_effect); } 

note I do not pass a single line.

+2
source

1) Quoting Wikipedia :

Single precision called "float" in the C language family, and "real" or "real * 4" in Fortran . This is a binary format that takes 32 bits (4 bytes) and its value has an accuracy of 24 bits (about 7 decimal digits).

So the marshal is like a bobber. You could test this one, either floating or double.

2) Quoting this Fortran 77 Tutorial :

Fortran 77 uses the so-called link call paradigm. This means that instead of simply passing the values โ€‹โ€‹of the function / subroutine to the arguments (default), the memory address of the arguments (pointers).

Pass each parameter by reference.

0
source

All Articles