View previous topic :: View next topic |
Author |
Message |
Developer1
Joined: 18 Mar 2010 Posts: 4
|
Posted: Wed Mar 24, 2010 11:57 am Post subject: Passing .NET arrays of floats gives strange result |
|
|
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:
Code: |
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:
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 |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8210 Location: Salford, UK
|
Posted: Mon Mar 29, 2010 8:44 am Post subject: |
|
|
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. |
|
Back to top |
|
 |
Developer1
Joined: 18 Mar 2010 Posts: 4
|
Posted: Mon Mar 29, 2010 2:29 pm Post subject: |
|
|
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
Code: | 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? |
|
Back to top |
|
 |
Emanuele
Joined: 21 Oct 2009 Posts: 78 Location: Bologna (Italy)
|
Posted: Mon Mar 29, 2010 3:36 pm Post subject: |
|
|
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:
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.
 |
|
Back to top |
|
 |
Emanuele
Joined: 21 Oct 2009 Posts: 78 Location: Bologna (Italy)
|
Posted: Mon Mar 29, 2010 3:59 pm Post subject: |
|
|
I modified the fortran code:
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.
Don't ask me why!!
Debugger, however, still says *invalid* B!  |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8210 Location: Salford, UK
|
Posted: Mon Mar 29, 2010 4:05 pm Post subject: |
|
|
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. |
|
Back to top |
|
 |
Emanuele
Joined: 21 Oct 2009 Posts: 78 Location: Bologna (Italy)
|
Posted: Mon Mar 29, 2010 4:12 pm Post subject: |
|
|
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. |
|
Back to top |
|
 |
Sebastian
Joined: 20 Feb 2008 Posts: 177
|
Posted: Mon Mar 29, 2010 10:56 pm Post subject: |
|
|
Would this code work:
Code: | 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. |
|
Back to top |
|
 |
Emanuele
Joined: 21 Oct 2009 Posts: 78 Location: Bologna (Italy)
|
Posted: Tue Mar 30, 2010 9:59 am Post subject: |
|
|
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.
Last edited by Emanuele on Tue Mar 30, 2010 1:12 pm; edited 2 times in total |
|
Back to top |
|
 |
Emanuele
Joined: 21 Oct 2009 Posts: 78 Location: Bologna (Italy)
|
Posted: Tue Mar 30, 2010 12:36 pm Post subject: |
|
|
To make some more confusion, I tried passing a third vector to the subroutine:
Code: | 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.
 |
|
Back to top |
|
 |
Developer1
Joined: 18 Mar 2010 Posts: 4
|
Posted: Tue Mar 30, 2010 1:49 pm Post subject: |
|
|
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:
Code: |
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? |
|
Back to top |
|
 |
|