JNA with Fortran-Java #16999/HEAD / v10 |
Tags:
not added yet
FORTRAN 90/95 and Java interoperability using JNATable of Contents
This section will introduce the use of JNA (Java Native Architecture) for direct Java/FORTRAN interoperability. JNA has been originally developed to allow for easy Java and C/C++ communication. It does not burden the developer with JNI management and other intermediate files/APIs to In contrast to JNI wich supports static interoperability JNA uses dynamic dispatching at runtime to connect to native DLL directely from Java. JNA's design aims to provide native access in a natural way with a minimum of effort. No boilerplate or generated code is required. While some attention is paid to performance, correctness and ease of use take priority. Examples for C/C++ are available, however the use of FORTRAN within the scientific community is as much as important. It can be achieved with the 'out-of-the-box' JNA library. The objective of this section is to show how to craft, compile, and link FORTRAN code to be accessible directly from Java using JNA. The following sections show different examples of JNA/FORTRAN interoperability. For general information about JNA and C/C++ examples please look at the JNA website Calling a FORTRAN Function/Subroutine with scalar arguments by value from Java.The following example function takes two arguments and returns their product.
FUNCTION mult(a, b) BIND(C, name='foomult') INTEGER,VALUE :: a,b INTEGER :: mult mult = a * b END FUNCTION The FORTRAN function above can be referenced and fetched using JNA: interface F95Test extends com.sun.jna.Library { F95Test lib = (F95Test) Native.loadLibrary("F90Dyn", F95Test.class); int foomult(int a, int b); }
... int result = F95Test.lib.foomult(20, 20); assert result == 400; ...For more details on compilation/linking see further below. Calling a Function/Subroutine with scalar arguments by reference.To call a subroutine with arguments by reference, you shall not use the VALUE keyword on FORTRAN argument declaration. Now you can assign new values to the arguments, that will be later visible to Java.SUBROUTINE ffunc(a, b) BIND(C,"reffunc") INTEGER :: a,b a = 3 b = 5 END SUBROUTINEThe Java interface method needs to be modified to support call by reference via the JNA API ByReference classes. ... void reffunc(ByReference a, ByReference b); ... The reffunc subroutine will be called as follows: ... IntByReference a = new IntByReference(0); IntByReference b = new IntByReference(0); F95Test.lib.reffunc(a, b); assertEquals(3, a.getValue()); assertEquals(5, b.getValue()); ... Now you create the int reference objects, pass them into reffunc and retrieve the values with .getValue(). Array ArgumentsSingle and Multidimensional arrays can be handled in JNA/Java and FORTRAN. Like with Strings, the length of the array has to be passed in with additional arguments.foo.f95:' SUBROUTINE inc(arr, len) BIND(C, name='fooinc') INTEGER,DIMENSION(len) :: arr INTEGER,VALUE :: len INTEGER :: i DO i = 1, len arr(i) = arr(i) + 30 END DO END SUBROUTINE SUBROUTINE arr2d(arr, m, n) BIND(C, name='arr2d') INTEGER,DIMENSION(m,n) :: arr INTEGER,VALUE :: m INTEGER,VALUE :: n INTEGER :: i,j DO i = 1, m DO j = 1, n arr(i,j) = arr(i,j) + 1 END DO END DO END SUBROUTINE The examples above show the declaration and the use of a one and two dimensional array as subroutine arguments. The array is dimensioned by the extra parameter, they are passed in as value arguments. The JNA/Java declaration part is shown below. Note that the multidimensional array, has to be one-dimensional in Java. FORTRAN will lay it out correctly by using the dimension lengths that are passed in. interface F95Test extends Library { ... void fooinc(int[] arr, int len); void arr2d(int[] arr, int m, int n); ... } The use if the one dimensional array is pretty simple. The other example required a bit management on the java side, that is not shown here. //1D int[] a = {1, 2, 3, 4, 5}; lib.fooinc(a, a.length); assertArrayEquals(new int[]{31, 32, 33, 34, 35}, a); //2D int[] a = {1, 2, 3, 4, 5, 6}; lib.arr2d(a, 3, 2); assertArrayEquals(new int[]{2, 3, 4, 5, 6, 7}, a); If a real Java multidimensional array needs to used in FORTRAN, it needs to be flattened into 1D, or you use an access method in Java to use a 1D Array in a 2D way. Not pretty but it works! String ArgumentsString arguments are always special, since Strings are represented differently in almost all languages. In FORTRAN, you declare a string argument as follows, note that the size of the string has to be passed in as an additional argument.The following function takes a string argument and verifies the content and length. The argument line is defined as a CHARACTER array, its length is passed as a second argument by value, and it is being used to dimension the length of the string. FUNCTION strpass(line, b) BIND(C, name='foostr') CHARACTER(len=b) :: line INTEGER, VALUE :: b LOGICAL :: strpass strpass = (line == 'str_test') .AND. (b == 8) END FUNCTION The Java/JNA prototype looks like this: ... boolean foostr(String s, int len); ... The application will need to pass in the string and obtain the actual string length. ... String test = "str_test"; boolean result = lib.foostr(test, test.length()); assertTrue(result); ... ModulesModules can be used to place all subroutines/functions that should be used via JNA, its good practice. A module allows for global data, an module level IMPLICIT NONE. Again, it is recommended to use the BIND keyword since the compiler might alter the subroutine name in the DLL otherwise, since it is a different scope. MODULE test IMPLICIT NONE CONTAINS SUBROUTINE ffunc(a, b) BIND(C,"reffunc") INTEGER :: a,b a = 3 b = 5 END SUBROUTINE END MODULE test The example above the subroutine ffunc can still be called as reffunc from JNA/Java. TYPE ArgumentsType arguments for functions can be handled too. This allows the passing of complex objects directly from Java to FORTRAN. Lets suppose you have the following FORTRAN code, that defines a TYPE for a City and a subroutine typepass that takes such an argument. MODULE test IMPLICIT NONE TYPE :: City INTEGER :: Population REAL(8) :: Latitude, Longitude INTEGER :: Elevation END TYPE CONTAINS SUBROUTINE typepass(c) BIND(C, name='footype') TYPE(CITY) :: c c%Population = c%Population + 1000 c%Latitude = c%Latitude + 5 c%Longitude = c%Longitude + 5 c%Elevation = c%Elevation + 9 END SUBROUTINE END MODULE test Both the TYPE and the subroutine are placed in a module. Now lets look at the JNA/Java counterpart that defines the interface for typepass: import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Structure; public static class City extends Structure { public int Population; public double Latitude, Longitude; public int Elevation; } interface F95Test extends Library { void footype(City c); } There is an Java class called City that must have the identical internal layout to its FORTRAN TYPE. The names, however, do not matter. It also has to be subclass of Structure which is defined in the JNA API. Note that all fields of City have to be public to allow JNA to compute its size. The F95Test method again used the BIND name and the City argument. An application will instantiate theCity object and pass it in as usual. ... City city = new City(3000, 0.222, 0.333, 1001); F95Test.lib.footype(city); assertEquals(4000, city.Population); assertEquals(5.222, city.Latitude, 0.0001); assertEquals(5.333, city.Longitude, 0.0001); assertEquals(1010, city.Elevation); ... Pitfalls and Obstacles
Data type mappingThe following table shows equivalent data types between FORTRAN and Java, ehen passed by value
Setting up your Java projectYou can use any IDE to develop your JNA supported Java code, as long as you make the file jna.jar a part of your classpath. This is the only library you need! See the References section for download. Dynamic Library GenerationThe following sections will provide some help for managing the build process using different compilers. GNU's compiler collection and the G95 spin-off, as well as the Intel Compiler suite seem to be the most important tools for the general developer.G95G95 allows compiling and linking into a DLL. Note that G95 is not a part of the GNU compiler collection. To compile and link a FORTRAN source into a DLL use the following flags for GCC tools:Compile a FORTRAN source into an object file: g95 -fno-underscoring -c -g -o build/ftest.o ftest.f90 Link the DLL: g95 -Wl,--add-stdcall-alias -shared -o dist/libF90Dyn.dll build/ftest.o Note that you have to use G95 for linking too. This ensures for linking the right FORTRAN runtime libraries into your DLL GNU GFortranGFortran allows compiling Fortran code into a shared library (.so on Linux) for use with JNA: Compile a FORTRAN source into an object file: gfortran -fno-underscoring -fPIC -c -g -o build/ftest.o ftest.f90 Link the .so: gfortran -shared -o dist/libftest.so ftest.o Note that you have to use GFortran for linking too. This ensures for linking the right FORTRAN runtime libraries into your shared object. NOTE: These instructions have been tested on Ubuntu Natty only. Intel ifcTBDReferences and Links
|
Navigation Bar for Object Modeling System
Resources:
Downloads You must login to see this link. Register now, if you have no user account yet. OMS API Javadoc Publications & Presentations Annotation Reference DSL Reference Handbook 3.0 (Draft) Frequently Asked Questions (FAQ) OMS License (LGPL 2.1) New Users: 1. Get an ALM account 2. Join the OMS project Contact Us: Jack Carlson Coordinator, OMS Laboratory OMS Laboratory Jack.Carlson@colostate.edu (970) 492-7323 Olaf David Director, OMS Laboratory odavid (at) colostate.edu (970) 491-8026 |