How To program in Java for SPIS-NUM

 

 

 

Some information on Java language itself and its proper usage in SPIS-NUM is provided here.

The first paragraphs can be useful for beginners in Java. The last ones shall be more useful for advanced programmers. They may even not be needed even by intermediate users who only handle top level Java objects (Plasma, VolDistrib…) in the highest-level object Simulation (in particular for some of the last considerations, other users don’t be scared, you don’t need to care about that!).

 

 

Finding documentation on Java

A lot of documentation can be found on Java on the SUN web site http://java.sun.com.

More specifically the following URL can be useful:

-         a tutorial on Java basics: http://java.sun.com/docs/books/tutorial/java/TOC.html

-         the API documentation (Application Program(ming) Interface): http://java.sun.com/j2se/1.4/docs/api/ or http://java.sun.com/j2se/1.5/docs/api/

Many other data (html and a few printable books) can be found on SUN site and elsewhere over the Internet.

Traditional books can of course also be purchased but should probably be restricted to a first linear reading to come to grips with Java. Html documentation is much more efficient for later reference (especially for the Java API, and SPIS-NUM API of course also!).

NB: when working with SPIS-NUM you�ll mostly use:

-         SPIS-NUM API documentation (JavadDoc generated html documents in documentation folder), in its public (for using from the outside as a library) or private version (for modifying)

-         Java language reference documentation (http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html or your preferred book)

-         but little Java API since few Java libraries are used in SPIS-NUM (contrarily to most Java developers, not working in scientific computing)

 

 

Documentation of SPIS-NUM: Javadoc

As in any Java code, the main source of documentation is the Javadoc-generated html documentation. The usage of this documentation is documented in the “How to understand SPIS-NUM architecture�? page (NUM architecture.html). The generation of Javadoc documentation is briefly described here. More can be found at http://java.sun.com/j2se/javadoc.

The basic idea is to write special comments before any important code component, so that they can be handled by Javadoc to generate html documentation pages. These comments:

-         are enclosed between /** and */, hence considered as comments by Java compiler but differentiated by Javadoc from regular comments thanks to the second star in /**.

-         are generally used before the following components to document them (a comment alway refers to the component that follows the comment):

-         class declarations (class and file headers indeed)

-         class fields (class variables)

-         class constructors

-         class methods

-         but not before lower level components (method variables, local variables)

-         support Javadoc tags starting with @, the main ones are:

-         at routine level: @param, @return, @see (the text following the tag describes the method parameters or returned object, and generates an hyper-link in the case of @see)

-         at class level: @author, @version

-         support many html instructions (tables, links, etc. see e.g.the version control table in each SPIS-NUM class header)

See the existing SPIS-NUM classes for examples, and the javadoc generated documentation for the results (../API/public/index.html)

The html can be generated from the source through one of the following methods:

-         the Project/Generate Javadoc menu in Eclipse

-         the javadoc instruction in command line. Try e.g. “javadoc -private -breakiterator -d doc -version -author spis/*/*/*.java�?.

 

 

Where are SPIS-NUM sources in SPIS release?

The working directory, form which the sources can be found is SpisNum/src. Consistently with Java rules, sources belonging to the package spis.xx.yy are in the directory spis/xx/yy (hence in SpisNum/src/spis/xx/yy).

As usual in Java, and in order to simplify the integration in SPIS framework, all SPIS-NUM classes (*.class) (and sources (*.java)) are also grouped in a single jar file spis.jar. In this release you should have this spis.jar file in SpisNum/src, and another copy of this spis.jar file located in SpisNum/build/Lib directory. This is the one executed by the code! Don’t forget to update it after modification. See the “How to transfer my SPIS/NUM java modifications from Eclipse to SPIS framework�? page (NUM integration in framework.html) to learn how to later integrate your modified SPIS-NUM Java sources into SPIS.

A jar file contains tarred Java classes (and possibly sources). It is very similar to a tar file. The sources can be extracted thanks to the jar instruction (jar comes with Java Development Kit JDK): �jar xvf spis.jar�?.

 

 

How to edit and modify SPIS sources?

You can of course edit SPIS-NUM Java sources with any ASCII-file editor.

There is a much better way yet, which is using an Integrated Development Environment (IDE).

One of the most advanced one for Java is Eclipse (http://www.eclipse.org). It was demonstrated during SPIS course at Kiruna (..\Courses\sw6\Roussel_SPISNUM.ppt), and is strongly recommended as development tool for SPIS-NUM. It offers the following very powerful features:

-         Source editing

-         GUI debugging

-         Syntax correction (bad syntax is underlined in red while typing)

-         Automatic completion (type ctrl-space)

-         Hyper-text navigation (press ctrl and click on a class, method, class variable�)

-         “Javadoc compatible�? (Java doc pop-ups when mouse is on a variable, class, method…)

In practice you�ll have to build an Eclipse project:

1.      Declare a new project, with name e.g. SpisNum (you can leave the default location workspace/MyProjectName or change it, but don’t use SpisNum/src or you’ll have difficulties in import)

2.      Import sources: in File/Import… menu choose “File System�?, then browse to select SpisNum/src as the directory from where to import. There, select the spis folder in src directory (possibly only filtering *.java files)

3.      Finally import lapack library: select your project then in the dialog box generated by the Project/Properties menu choose Java Build Path / Libraries / Add External JARs and browse to include the blas.jar, f2jutil.jar, lapack.jar and xerbla.jar files (currently available in SpisNum/src).

Eclipse should display no more errors and you should be able to start coding and debugging in Eclipse.

 

 

How to debug my new/modified SPIS sources?

The best way is to run SPIS-NUM under Eclipse debugger, which is very powerful (similar to most debuggers).

Since Eclipse cannot be invoked within SPIS framework, SPIS-NUM must be run independently of the framework.

For that, the meshes, local and global parameters, which are normally passed by the framework to NUM must be saved by the framework (in two files named globalParOut.gp and localParOut.lp, the latter containing both the local parameters and the meshes) and then loaded by SPIS-NUM (same files to be renamed globalParIn.gp and localParIn.lp,) when run as standalone code within Eclipse:

-         Have globalParOut.gp and localParOut.lp files created:

-         run the framework: define your geometry, mesh, etc. and run the Solver. It will create these files into you temporary directory (/tmp/tmpspis… as displayed on the screen when launching SPIS). Don’t worry if ever the Solver crashes during simulation, it creates these files before starting.

-         Copy and rename these files (globalParIn.gp and localParIn.lp) in your Eclipse working directory (e.g. workspace/SpisNum)

-         Run SPIS-NUM under Eclipse as a standalone code to debug your source:

-         Select the class containing a main() method (mimicking SPIS framework): Top class in spis.Top.Top package

-         Click the Run/Debug As/Java Application menu => it starts (next times you can use F11 to �debug last�)

-         In the menu mimicking SPIS framework you�ll have to successively:

-         Click at the bottom of the Console window of the debug perspective where the menu is displayed, exactly where your input is expected

-         First choose “i�?: import (the files globalParIn.gp and localParIn.lp are read)

-         Then choose the simulation you want to run: certainly SimulationFromUIParams (“sui�?), or maybe LEO example (“el�?), or GEO (“eg�?, “eg2�?), or your new simulation (add it to Top menu)…

-         Eventually time-integrate the dynamics: “int�?

You can debug your code when running it and view your results through the debugger if it terminates without crashing (no transfer of the results to the framework is possible at this level for graphical plotting, the best it to execute your code again within the framework when it no longer crashes, although a dump of the results into a file might be implemented in the future to import t it in the framework, similarly to what is done for meshes in the opposite direction).

As many other things, this way of working can be modified in next versions.

 

 

Java features important to SPIS-NUM

Basic Object Oriented Programming (OOP) and Java concepts were presented during SPIS course (6th SPINE meeting, http://spis.onecert.fr/spine/meeting/spineM6/index.html, Kiruna, 15-17 March 2004) and these slides can be found in this documentation (..\Courses/SPISNUM_old_2.95.pdf),

A few important features are recalled here (with some extra ones w.r.t. the slides):

 

-         Java naming conventions (upper/lower case usage): in class/methods/fields naming words are separated by upper case letters, but methods/fields/instance names start with lower case contrarily to class/constructor names. Example: MyClass myInstance = new MyClass(myPassedVariable);

-         Good OOP practice (not specific to Java): define private fields and public methods. When doing so, the implementation of the class can be modified provided the public method interface is unchanged. Many of the private fields can be accessed through �getters� and �setters� (e.g. the getter: public ThatFieldType getThatField() {return thatField;}). This rule is strictly respected in SPIS-NUM and shall be enforced for extensions. The only (relative) exceptions are:

-         Some fields are protected, not private, so as to be accessible from classes in the same package (usually derived classes). A change in such a class may thus request changes in classes of the same package.

-         A few default global data (particle types, material parameters, sampling parameters, etc.) are necessarily stored as class fields in Java. There looked to be no reason not to address them directly. They were thus declared public. These are the static fields of the classes Global, SpisDefaultPartTypes, SpisDefaultMaterials, SpisDefaultSampling, etc.of package spis.Top.Default.

 

-         Variable passing: variables are passed by reference (which is different from pointers or values). The same is true for affectation. Consequences:

-         myInstance = oldInstance; does not actually copy the object but the reference: myInstance is a reference to the same old object (reference can be considered as a pointer here)

-         If you want to make an actual copy of an object: use the copy constructor, which accepts as parameter the old to-be-copied object ex myCopiedScalSurfField = new ScalSurfField(myOldScalSurfField); Automated methods (like clone) must not be used because they cannot know what must be copied (almost everything, most ScalSurfField fields in that example) and what must not (the surface mesh this ScalSurfField “lives�? on, to which the surface field simply points (the pointer/reference must be copied, not the whole mesh!))

-         If a component of a passed variable is modified the original is modified: myMethod(myObject) {myObject.someField = otherFieldValue;} modifies the original of the passed object

-         If a passed variable is “re-affected�?, the original is not modified: myMethod(myObject) {myObject = otherOject;}, or myMethod(myObject) {myObject = new MyClass();}, does not modify the original of the passed object because myObject = xx has the mere consequence that the local myObject now refers to (points to) xx. The original is simply no longer referenced.

-         Consequence of the two previous points: if you want to return a simple float result in the passed variable of a method/subroutine (no the returned object of a method/function) don�t modified a passed float x, it won’t work, pass float[] x and modify x[0].

 

-         Result sub-types: a method that returns an object as a result of its action can either chose itself the object subtype or let the code calling it make that choice. Example: a sampling routine can return a basic particle list PartList or a more detailed particle list RichPartList, the latter being a derived class of the former. If the result is returned as a modification of a passed object (of PartList or RichPartList type here), the sub-type is chosen by the caller (public void sample(PartList pl, …) method, which cannot reallocate the object pl to another subtype, or the link is lost, see section above). If the it is returned as the returned object of the method (public PartList sample(…) method, which would be a function, not a subroutine in a Fortran vocabulary), the sub-type is chosen within the method. Either of these possibilities can be better suited to a situation or another. In the sampling example above, both choices are offered. The particle list subtype can be imposed by the caller (e.g. to generate a list of the same subtype as the list it must be injected into (this list is a plasma source)) by using the public void sample(PartList pl, float dt) method of SurfDistrib class (“subroutine�?). It can also be left to the sampling method (e.g. to let it choose its most accurate/efficient way to do the sampling, since any type is supported by the caller, that will for instance compute SC interactions correctly whatever the sub-type) by using the public PartList sample(float dt) method of SurfDistrib class (“function�?).

 

-         Getters and setters � (improper) usage of getters to modify an object field: as stated above, class fields are private (or protected) and accessed by public �getters� and �setters�, public XxxType getXxx() and public void setXxx(yyy). Getters are much more used than setters because fields are often defined in the constructor or as a result of a method invocation. If a private field is accessed by the corresponding public getter, it can be tempting to modify it and consider that the modification is taken into in account in the containing class. Example: Table t; float[] array = t.getValues(); array[i] = 10.0f; It can be tempting because in most cases it will work. But this is not a correct may of programming because the reason why the float[] field values is private is that it can be implemented differently in some cases (e.g. storing only non-zero values, it is the case for matrices), in which case the array returned by the getter is a temporary array built by the getter. Modifying it does not modify the original data in such a case. The right way of programming is to use a setter after the modification: t.setValues(array); in the previous example. If ever this particular implementation of the array only stores non-zero values, the setter will properly condense the modified expanded array in the specific condensed storage (maybe not very efficiently on this example but this is another story). If the full expanded array is really stored, invoking the setter will only induce a small cost since it will only result in a reference copy (onto itself).