Even the path is corrected, it still cannot run, since the argument type should {"double*", "double*"}.
Here is my memo on calling dll created by gfortran using NETLink:
Advantages of NETLink as compared to Mathlink:
- Fortran functions and subroutines can be called using NETLink without writing an additional C wrapper which is necessary in Mathlink.
- NETLink can access all the functions and subroutines in the fortran code by calling the dll file, not only one.
And it seems to me NETLink is faster than Mathlink.
- Calling a fortran function
Suppose we have a fortran code testfunction.f90
REAL(8) FUNCTION testfunction(x,y)
REAL(8), DIMENSION(2) :: x
REAL(8) :: y
testfunction = (x(1)+x(2)) * y
END FUNCTION
We can compile it and build a dll
gfortran -c testfunction.f90
gfortran -shared -mrtd -o testfunction.dll testfunction.o
Now the function testfunction(x,y)
in testfunction.dll can be called after loading the .NET/Link package
Needs["NETLink`"]
ReinstallNET["Force32Bit" -> True]; (* or InstallNET["Force32Bit"->True] *)
(* set to the directory of the notebook, and the dll file is in the same dir *)
SetDirectory[NotebookDirectory[]];
path = FileNameJoin[{Directory[], "testfunction.dll"}];
TestFunction = DefineDLLFunction["testfunction_", path, "double", {"double[]", "double*"}];
TestFunction[{1.0, 2.0}, 3.0]
gives the correct result 9.0
.
Explanations:
DefineDLLFunction
: the first argument is the function name to be called. It has changed from testfunction
to testfunction_
, and might be TESTFUNCTION
or other depending on the fortran compiler. path
is the complete path to the dll file. "double"
is the return type. The last argument contains the types of the arguments. Note the presence of []
for an array and *
for others.
If *
is missing, there will be an error message saying
NET::netexcptn: A .NET exception occurred:
System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
at Wolfram.NETLink.DynamicDLLNamespace.DLLWrapper...testfunction_(Double[],Double).
If []
is missing or written as *
by mistake, the error message is
NET::methodargs: Improper arguments supplied for method named testfunction_."
Before making revisions to the dll file, one should use ReinstallNET["Force32Bit" -> True]
to quit and restart the .NET runtime
- Calling a fortran subroutine
see also the post here
testsubroutine.f90
SUBROUTINE testsubroutine(x,y,z)
REAL(8), DIMENSION(2), INTENT(in) :: x
REAL(8), INTENT(in) :: y
REAL(8), DIMENSION(2), INTENT(out) :: z
z(1) = x(1) * y
z(2) = x(2) * y
RETURN
END SUBROUTINE
testsubroutine.dll can be built as before. In Mathematica, after loading NETLink and ReinstallNET["Force32Bit" -> True]
,
path2 = FileNameJoin[{Directory[], "testsubroutine.dll"}]
TestSubroutine = DefineDLLFunction["testsubroutine_", path2, "void",
{"Double[]", "Double*", "Double[]"}]
Now we should create a .NET object, which is to be sent to testsubroutine_
at the place of z
to store the results
(* Any real or integer numbers can be put in the list.
"System.Double[]" is necessary if any of the numbers is an integer. *)
res = MakeNETObject[{0, 0.}, "System.Double[]"]
Now let's test a case:
TestSubroutine[{1., 2.}, 3., res] (* res receives the calculated results *)
(* translate the .NET object results into a Mathematica expression *)
NETObjectToExpression[res]
The results are the desired {3., 6.}.