Silverfrost Forums

Welcome to our forums

Passing .NET arrays of floats gives strange result

24 Mar 2010 10:57 #6209

Dear all,

I have Visual Studio 2005 and use the FTN95 Personal Edition at the moment (how do I find the version number?). I have the Fortran code compiled into a DLL which I refrence in my calling code. I can see the Fortran function fine.

My task is to test whether I can do calculations using Fortran legacy code in a .NET v2 application.

The problem I encounter is that when I pass to my Fortran code two same size .NET arrays of floats and add the individual array items together to return a new array, I get quite some garbage.

This code generates the arrays in C#.NET:

            const int arraysize = 10;
            float[] a = new float[arraysize];
            float[] b = new float[arraysize];

            for (int i = 0; i < arraysize; i++)
            {
                a[i] = System.Convert.ToSingle(i.ToString());
                b[i] = System.Convert.ToSingle('0.' + i.ToString());
            }
            a[0] = -1000F;
            b[arraysize - 1] = -1000F;

            float[] c = new float[arraysize];
            for (int i = 0; i < c.Length; i++)
            {
                if (a[i] == -1000F || b[i] == -1000F)
                {
                    c[i] =-1000F;
                }
                else
                {
                    c[i] =  a[i] + b[i];
                }
            }


            float[] d = FortranFunctions.Add(a, b);

The two arrays to add together are: a: -1000 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 b: 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 -1000

The task is that if the value is -1000, assign it, otherwise add the items of the arrays together.

The result expected is array c: -1000 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 -1000

I pass arrays a and b to the following Fortran code:

REAL FUNCTION DIRECTCALL_ADD(A,B) RESULT(C)
    ASSEMBLY_INTERFACE(NAME='Add')
    REAL A(0:)
    REAL B(0:)
    REAL C(0:9)
    D=-1000.00
    
    DO i=0,9
        IF (A(i).EQ.D .OR. B(i).EQ.D) THEN
            C(i)=D
        ELSE
            C(i)=A(i)+B(i)
        ENDIF
    END DO
    
END FUNCTION

Apart from the result array being fixed size at the moment and the compiler moaning about my checking on the value -1000, the problem is more fundamental. The Fortran result array d: -1000 1 2.1 3.2 4.3 5.4 6.5 7.6 8.7 9.8 When I debug and step through the Fortran code, I can see the Fortran array A and its members, but I cannot access Fortran arrays B or C. Hovering over B gives 'B, REAL*4 (Invalid)'. Hovering over C gives 'unknown variable'.

I have these options set in the Fortran project (others installation default): Configuration Properties Compiler Options Miscelleaneous -Debug Target: somelocation\Modules.Calculations.Fortran.dll -Output Filename: somelocation\Modules.Calculations.Fortran.dll Linker Options Linker Options -Class name: Modules.Calculcations.Fortran.FortranFunctions -Interface only: yes

So, my question is: what is going wrong?

Regards, Alex

29 Mar 2010 7:44 #6226

I do not have the time to check this out for you and my C# is a little rusty but I guess that the C# arrays a essentially 'safe arrays' and they are not stored as contiguous blocks in the way that the Fortran expects. For a one-dimensionall array you might get a contiguous block with some kind of header data.

Try a very simple test in which you create a simple array directly, set its first value, pass it to Fortran and then print out the first value.

29 Mar 2010 1:29 #6229

Nevertheless, the first array is okay. It is the second array where the problem lies.

The most instantanious arrays that can be created in .NET is via a System.Collections.Generic.List<float>. First, filling the lists as above and then calling the ToArray() method.

I have tried to pass A.ToArray and B.ToArray() into the line

float[] D = Modules.Calculations.Fortran.FortranFunctions.Add(A.ToArray(), B.ToArray());

This way, these arrayes are the 'freshest' I can ever generate. I still get the above result.

So, what do I have to do to .NET arrays to pass them to a Fortran function?

29 Mar 2010 2:36 #6230

I can confirm the problem. I got the same results as Developer1, also traslating the C# in VB. I also tried passing two identical vectors but the second (B) is invalid for Fortran debugger. Here is my VB code:

 Dim a(9), b(9), c(9), d(9) As Single
        For i As Integer = 0 To 9
            a(i) = CSng(i)
            b(i) = CSng(i)
        Next
        a(0) = -1000
        b(0) = -1000

        For i As Integer = 0 To 9
            If (a(i) = -1000 Or b(i) = -1000) Then
                c(i) = -1000
            Else
                c(i) = a(i) + b(i)
            End If
        Next

        d = FortranFunctions.Add(a, b) 

Vector d results: -1000.0 -1000.0 3.0 5.0 7.0 9.0 11.0 13.0 15.0 17.0

Looking at Developer1's and mine results, it seems that the first A element is added to the second B element, the second A element to the third B element and so on. 😒hock:

29 Mar 2010 2:59 #6231

I modified the fortran code:

 REAL FUNCTION DIRECTCALL_ADD(A,B) RESULT(C) 
    ASSEMBLY_INTERFACE(NAME='Add') 
    REAL, intent(in):: A(:), B(:)
    REAL:: C(ubound(A,1)) 
    D=-1000.00 
    
    DO i = 1, 10 
        IF (A(i).EQ.D .OR. B(i).EQ.D) THEN 
            C(i)=D 
        ELSE 
            C(i)=A(i)+B(i) 
        ENDIF 
    END DO 
       
END FUNCTION 

Results are correct. 😒hock: 😒hock: 😒hock: 😒hock: 😒hock: Don't ask me why!! Debugger, however, still says invalid B! :!: :?: :!:

29 Mar 2010 3:05 #6232

The place to look in FTN95.chm is .NET Platform->.NET Programming->Calling Fortran from other .NET languages

This provides an example and explains that the index starts at zero and the 'column major' ordering of the elements is different in C# and Fortran.

29 Mar 2010 3:12 #6233

Dear Paul,

Developer1's code looks perfectly consistent with provided example. Moreover in this case the arrays are one-dimensional, so there should be no problems with the dominant index.

29 Mar 2010 9:56 #6237

Would this code work:

REAL FUNCTION DIRECTCALL_ADD(A,B) RESULT(C) 
    ASSEMBLY_INTERFACE(NAME='Add') 
    REAL A(1:) 
    REAL B(1:) 
    REAL C(1:10) 
    D=-1000.00 
    
    DO i=1,10 
        IF (A(i).EQ.D .OR. B(i).EQ.D) THEN 
            C(i)=D 
        ELSE 
            C(i)=A(i)+B(i) 
        ENDIF 
    END DO 
    
END FUNCTION 

If it does it would hint at a shift when arrays are passed, to simplify the transition from zero-based (c#) to default 1-based (fortran) arrays.

30 Mar 2010 8:59 (Edited: 30 Mar 2010 12:12) #6242

Dear Sebastian, Your code works properly, too.

What I cannot understand are:

  1. why the zero-index produces a shift which affects only the second array passed to the sub (the B(0) element is set to 1.4E-44);

  2. why, in both zero and one-index cases, the visual studio debugger is able to show only the first array values while not the second ones, even if the two arrays are identical.

30 Mar 2010 11:36 #6245

To make some more confusion, I tried passing a third vector to the subroutine:

 REAL FUNCTION DIRECTCALL_ADD(A,B,E) RESULT(C) 
    ASSEMBLY_INTERFACE(NAME='Add')
   
    REAL:: A(0:), B(0:), E(0:) 

In this case arrays A and B were passed correctly, while array E showed that nasty shift (E(0) value 1E-44). Probably this bug (may I call it 'bug'?) affects only the last argument.

The following shot to show the Local Variable window of Visual Studio. The image refers to a break-point inserted before the end subroutine statement.

http://img43.imageshack.us/img43/8740/catturavs.gif

30 Mar 2010 12:49 #6246

Thank you all for replying.

I first tried Sebastian's changes to let the arrays start 1. The code executed corretcly, but array B was still shiwn as invalid.

I then combined Sebastian's and Emanuele's approach:

REAL FUNCTION DIRECTCALL_ADD(A,B,C) RESULT(D)
    ASSEMBLY_INTERFACE(NAME='Add')
    REAL A(1:)
    REAL B(1:)
    REAL C(1:)
    REAL D(1:10)
    F=-1000.00
    
    DO i=1,10
        IF (A(i).EQ.F .OR. B(i).EQ.F) THEN
            D(i)=F
        ELSE
            D(i)=A(i)+B(i)
        ENDIF
    END DO
    
END FUNCTION

Array C is invalid as predicted.

So, any idea why that might be?

Please login to reply.