AMAPstudio

User Tools


A Java - Fortran connection with JNA (a test with Organon by the Oregon State University, USA)

fc - 13.8.2014

To prepare the incoming introduction of the Organon model (David W. Hann, Oregon State University) in Capsis, a check has been run with Nathaniel Osborne to make sure the Java - Fortran connection was possible.

These notes may help for a next Java - Fortran connection.

The work was conducted on a Windows laptop (Dell E6510, ref cire857), running Windows 32 bits, with a 32 bits jdk 1.7.0_67. The Organon dlls have been compiled in 32 bits.

The dlls have been moved into the capsis4/ext/windows/ folder (ORG*.dll)

Running Capsis once in a terminal changes the PATH in this terminal, so the ext/windows/ folder can be found with the dlls it contains. Then, the Check program can be launched in the same terminal (see command below).

The connection relies on the JNA technology, everything is written in Java, no need for headers or native recompilation (easier than JNI).

Excellent links:

The check program is in capsis4/src/sandbox/, called OrganonTest.java

package sandbox;
 
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.ptr.*;
 
/**
 * A test of Java - Organon maping with JNA.
 *
 * # To run it under Windows:
 * # Note: Organon dlls need Windows 32 bits + jdk 32 bits
 * cd .../capsis4
 * # Calling capsis adds the path to the 32 bits dlls in the system path
 * capsis
 * java -cp class;ext\* sandbox.OrganonTest 
 *
 * @author F. de Coligny - august 2014
 */
 
public class OrganonTest {
 
	static {
		// Set and print jna.library.path
		System.setProperty ("jna.library.path", System.getProperty ("java.library.path"));
		System.out.println ("jna.library.path: "+System.getProperty ("jna.library.path"));
 
	}
 
	// Mapping ORGEDIT.dll
	public interface Orgedit extends Library {
		Orgedit INSTANCE = (Orgedit) Native.loadLibrary("ORGEDIT", Orgedit.class);
 
		void get_orgedit_edition_(FloatByReference edition);
 
		void prepare_ (IntByReference VERSION, IntByReference NPTS, IntByReference NTREES,
				IntByReference STAGE, IntByReference BHAGE, int[] SPECIES, int[] USER,
				IntByReference IEVEN, float[] DBH, float[] HT, float[] CR, float[] EXPAN,
				float[] RADGRO, float[] RVARS, int[] SERROR, int[] TERROR, int[] SWARNING,
				int[] TWARNING, FloatByReference IERROR, IntByReference IRAD, float[] GROWTH,
				float[] ACALIB);
	}
 
	public static void main(String[] args) {
 
		// Simple Organon call: ask for the edition number
		System.out.println ("calling get_orgedit_edition_()...");
		FloatByReference edition = new FloatByReference (0);
		Orgedit.INSTANCE.get_orgedit_edition_ (edition);
		System.out.println ("edition: "+edition.getValue ());
 
		// Trying to call the prepare() function
 
		// Step 1: vectors initialisation
		int[] SPECIES = new int[2000];
		int[] USER = new int[2000];
		float[] DBH = new float[2000];
		float[] HT = new float[2000];
		float[] CR = new float[2000];
		float[] EXPAN = new float[2000];
		float[] RADGRO = new float[2000];
		FloatByReference IERROR = new FloatByReference (0);
		float[] RVARS = new float[30];
		int[] SERROR = new int[13];
		int[] TERROR = new int[2000*6];
		int[] SWARNING = new int[8];
		int[] TWARNING = new int[2000];
		float[] GROWTH = new float[2000];
		float[] ACALIB = new float[3*18];
 
		// Step 2: populate the vectors
		IntByReference VERSION = new IntByReference (3); // Version of Organon to run (1, 2, 3)
		IntByReference NPTS = new IntByReference (1); // Number of sample points fixed at one
		IntByReference NTREES = new IntByReference (11); // Number of trees in the sample
		IntByReference STAGE = new IntByReference (24); // Stand age
		IntByReference BHAGE = new IntByReference (20); // Breast height age
		fillArray (SPECIES, new int[]{202,202,202,202,202,202,202,202,202,202,202}); // Species for each tree
		fillArray (USER, new int[]{0,0,0,0,0,0,0,0,0,0,0}); // Code for user thinnin
		IntByReference IEVEN = new IntByReference (1); // If the stand is even aged or not
		fillArray (DBH, new float[]{12.2f,10.0f,10.3f,13.6f,9.0f,16.0f,12.1f,8.5f,12.7f,13.3f,8.0f}); // Diameter at breast height for each tree (in)
 
		// Checking: we forget height values in HT, prepare will calculate them
		fillArray (HT, new float[]{93.0f,92.0f,87.0f,97.0f}); // Total height for each tree (ft)
		// the complete line fillArray (HT, new float[]{93.0f,92.0f,87.0f,97.0f,81.0f,98.0f,93.0f,78.0f,92.0f,95.0f,81.0f}); // Total height for each tree (ft)
 
		fillArray (CR, new float[]{0.387f,0.379f,0.381f,0.333f,0.387f,0.395f,0.550f,0.394f,0.415f,0.486f,0.396f}); // Crown ratio for each tree
		fillArray (EXPAN, new float[]{20f,20f,20f,20f,20f,20f,20f,20f,20f,20f,20f}); // Expansion factor for each tree (tpa)
		fillArray (RADGRO, new float[]{0f,0f,0f,0f,0f,0f,0f,0f,0f,0f,0f}); // User supplied estimates of radial growth (in)
		fillArray (RVARS, new float[]{125f,0f,0f,0f,0f,0f}); // Set of six indicator variables
		IntByReference IRAD = new IntByReference (0); // Indicator if radial growth measurements were entered
 
		// Step 3: call Orgedit.prepare (...)
 
		System.out.println ("HT: "+print(HT, 11));
 
		System.out.println ("calling prepare_()...");
		Orgedit.INSTANCE.prepare_ (VERSION, NPTS, NTREES,
				STAGE, BHAGE, SPECIES, USER,
				IEVEN, DBH, HT, CR, EXPAN,
				RADGRO, RVARS, SERROR, TERROR, SWARNING,
				TWARNING, IERROR, IRAD, GROWTH,
				ACALIB);
 
		System.out.println ("IERROR: "+IERROR.getValue ());
 
		System.out.println ("HT: "+print(HT, 11));
 
 
 
	}
 
	private static void fillArray (int[] dest, int[] source) {
		for (int i = 0; i < source.length; i++) {
			dest[i] = source[i];
		}
	}
 
	private static void fillArray (float[] dest, float[] source) {
		for (int i = 0; i < source.length; i++) {
			dest[i] = source[i];
		}
	}
 
	private static String print (float[] source, int len) {
		if (len <= 0) len = source.length;
		StringBuffer b = new StringBuffer ();
		for (int i = 0; i < len; i++) {
			b.append (source[i]);
			b.append (' ');
		}
		return b.toString ();
	}
 
}

To find the correct function names in the dlls, we used a program called Dependency Walker, it told us the function names should be in lowercase and that a '_' was to be appended at the end of the function names.

The int and float values sent to the functions are pointers: some results can be retrieved in them after the call, we used the JNA IntByReference and FloatByReference.

The arrays are simple float[] and int[].

The command to launch the test, from the capsis4/ install folder (calling capsis first adds the path to the windows 32 bits dll in the System PATH environment variable for the terminal in use, needed for OrganonTest, capsis can be closed immediately):

capsis
java -cp class;ext\* sandbox.OrganonTest

During the check, we omitted some values in the tree heights (HT) array. We could check at the end that the prepare () method in Fortran had computed the missing values.

documentation/java-fortran_connection.txt ยท Last modified: 2016/07/25 15:28 by coligny