VB.Net Calling Fortran DLL Multi-Dimensional Arrays

VB.Net Calling Fortran DLL Multi-Dimensional Arrays

I am using Visual Studio.Net 2003 and Visual Basic.Net and calling a Fortran Dll created in Intel Fortran 8.0.

Calling a Fortran Subroutine from Visual Basic with Single dimensioned arrays works perfectly:

Visual Basic Declare statement:

Public Declare Sub FCALL3 Lib "c: empIntel_FCALLDebugIntel_FCALL.dll" (ByRef xyz As Double)

Visual Basic Call Statement

Call FCALL3(xyz(1)) '<<--- Note the first position of the array as a single element

Fortran Subroutine:

subroutine FCALL3( xyz)

!DEC$ ATTRIBUTES DLLEXPORT :: FCALL3

!DEC$ ATTRIBUTES ALIAS :'FCALL3' :: FCALL3

!DEC$ ATTRIBUTES REFERENCE :: XYZ

Real*8 :: xyz(512)

! Body of FCALL

xyz(1) = 111.11d0

xyz(7) = 777.77d0

end subroutine FCALL3

'************************************The above works perfectly*****************************

However with a two dimensional array, I do not get the array values returned correctly

Visual Basic Declare Statement:

Public Declare Sub FCALL4 Lib "c: empIntel_FCALLDebugIntel_FCALL.dll" (ByRef xyz2 As Double)

Visual Basic Call Statement

Call FCALL4(xyz2(1, 1))

Fortran Subroutine:

subroutine FCALL4( xyz2)

!DEC$ ATTRIBUTES DLLEXPORT :: FCALL4

!DEC$ ATTRIBUTES ALIAS :'FCALL4' :: FCALL4

!DEC$ ATTRIBUTES REFERENCE :: XYZ2

! Variables

Real*8 :: xyz2(512,10)

! Body of FCALL

xyz2(1,1) = 11.d0

xyz2(1,2) = 12.d0

end subroutine FCALL4

<
FONT size=2>

The Array xyz2(512,10) does return back to Visual Basic.Net, but the array values are

received in Visual Basic as follows:

xyz2(1,1) = 11.d0

xyz2(1,2) = 0.d0

xyz2(47,7) = 12.d0

Why is the second value stored in row 47 column 7?

Any help would be greatly appreciated.

Thanks.

14 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

How are you declaring the arrays in VB? I don't see a Dim statement to do that in your code.

AFAIK, both VB and Fortran store 2-d arrays in memory in row-major order: element(1,1), element(2,1), element(3,1),..., element(n,1), element(1,2), element(2,2), element(3,2),..., element(n,2), etc. How you declared the arrays in VB would help explain the results you are seeing.

Mike D.

Steve Lionel (Intel)'s picture

I think you meant "column-major order", though I'll be honest and say I don't know offhand what order VB uses. I do know that in VB, arrays start at 0, unlike Fortran which start at 1.

Steve

This is the exact VB.Net code that is used to call these two Fortran subroutines:

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

Dim xyz(512) As Double, xyz2(512, 10) As Double

Dim inx As Integer, inx2 As Integer

' One dimensional Array Call

Call FCALL3(xyz(1))

' One dimensional Array Result

Me.TextBox3.Text = xyz(1).ToString

Me.TextBox4.Text = xyz(7).ToString

' Multi-dimensional Array Call

Call FCALL4(xyz2(1, 1))

' checking for the row/element change

For inx = 0 To 512

For inx2 = 0 To 10

If xyz2(inx, inx2) > 0 Then

MsgBox("value = " & inx.ToString & "," & inx2.ToString)

End If

Next

Next

' Multi-dimensional Array Result

Me.TextBox5.Text = xyz2(1, 1).ToString

Me.TextBox6.Text = xyz2(47, 7).ToString ' ,<<<--- this is the xyz2(1,2) result

End Sub

The results from each call are placed in TextBoxes.

The VB.Net declarations are as
follows

Public Declare Sub FCALL3 Lib "c: empIntel_FCALLDebugIntel_FCALL.dll" (ByRef xyz As Double)

Public Declare Sub FCALL4 Lib "c: empIntel_FCALLDebugIntel_FCALL.dll" (ByRef xyz2 As Double)

Note: Each declaration is only using a single element reference as the starting point.

VB.net arrays are 'zero-based' and store their array elements in the

opposite order from Fortran. Because you pass the array address to

Fortran using the (1,1) address, it lines up ok with (1,1) on the Fortran

end, but everything else would be off. Everything actually lines up in

memory like this:

VB.NET

(0,0)

(0,1)

(0,2)

(0,3)

(0,4)

(0,5)

(0,6)

(0,7)

(0,8)

(0,9)

(0,10)

(1,1)

VB.net arrays are 'zero-based' and store their array elements in the

opposite order from Fortran. Because you pass the array address to

Fortran using the (1,1) address, it lines up ok with (1,1) on the Fortran

end, but everything else would be off. Everything actually lines up in

memory like this:

VB.NET

(0,0)

(0,1)

(0,2)

(0,3)

(0,4)

(0,5)

(0,6)

(0,7)

(0,8)

(0,9)

(0,10)

(1,1)

I know that VB is zero based, both column and row and so the starting point
for VB is (0,0), but if I call the Fortran routine using (0,0) I still get incorrect results. Instead of returning the value in row 47 column 7, it simply returns the value from xyz2(1,2) is row 46 column 6.

i.e VB Call xyz2(1,1) --Fortran xyz2(1,2) returns value in xyz2(47,7)
i.e. VB Call xyz2(0,0) -- Fortran xyz2(1,2) returns value in xyz2(46,6)

I think that you should be calling the Fortran routine with a single beginning
reference point in the declare statement, but it may be that I will have to specify it as multi-dimensional and pass the actual array as (xyz2).

I am checking on the Microsoft Visual Studio.Net 2003 Help side now.

Still unresolved, but thanks for your feedback.

VB.net arrays are 'zero-based' and store their array elements in the

opposite order from Fortran. Because you pass the array address to

Fortran using the (1,1) address, it lines up ok with (1,1) on the Fortran

end, but everything else would be off. Everything actually lines up in

memory like this:

VB.NET Fortran

(0,0)

(0,1)

(0,2)

(0,3)

(0,4)

(0,5)

(0,6)

(0,7)

(0,8)

(0,9)

(0,10)

(1,0)

(1,1) (1,1)

(1,2) (2,1)

(1,3) (3,1)

(1,4) (4,1)

(1,5) (5,1)

(1,6) (6,1)

(1,7) (7,1)

(1,8) (8,1)

(1,9) (9,1)

(1,10) (10,1)

(2,0) (11,1)

(2,1) (12,1)

.

.

.

(47,5) (511,1)

(47,6) (512,1)

(47,7) (1,2)

...and so on. So it works out just like you said. Since you can't change

the lower bound on arrays in VB.net you've got a couple of choices:

1. change the vb.net end to declare the array as (511,9) and pass

the starting adress as (0,0)

2. change the fortran end to explicitly declare the lower bounds

of the indices as 0.

In either case, you will need to swap the array indices on one end or

the other.

Thanks for the feedback. I see what you mean.

It is still not clean enough for me.

I do not want to be swapping array elements with non-square matrices (m by n).

Thanks again.

You can make all the arrays in your VB program be one-based instead of the default zero-based by including an Option Base 1 statement at the top of your code before any procedure definitions.

You can override the zero-based default for any individual array by changing its declaration. For example, declaring an array Dim myarray(1 to 10, 1 to 10) will give you a 10x10 array with elements numbered 1 to 10 in each dimension instead of 0 to 9.

Steve was right above; I meant to say column-major order.

Mike D.

I guess I didn't read all the posts carefully. According to jparsly VB.NET arrays are in row-major order. This may be a difference between VB6 and VB.NET.

Mike D.

I know when VB.NET was first released, it didn't support OPTION BASE,
and I don't think you could specify ranges for the array bounds either.
I don't remember hearing that either feature had been added in the later
releases. Perhaps some who actually uses .net knows for sure?

It is stated Microsoftpolicy that vb.net arrays will always be zero based.
You'd better get used to it! ;-)

g.f.thomas's picture

In VB6 and below, arrays were 0-based and stored in column-major order. If you Option Base 1, VB6 arrays are Fortran like. In VB.NET, arrays are 0-based and stored in row-major order like C/C++/C#.

Ciao,
Gerry T.

Login to leave a comment.