An alternative implementation of orekit python wrapper based on Jpype and stubs generated by stubgenj. The interface is largely similar to the original JCC wrapped orekit version which is a more capable wrapper as it can subclass java classes, which Jpype cannot. The Jpype version is however easy to install, use and for most purposes sufficient.
Orekit (https://www.orekit.org/) is a low level library for space flight dynamics and is written in Java. The java API is located at: https://www.orekit.org/site-orekit-12.0.2/apidocs/index.html
The original Orekit python wrapper based on JCC is located at:
Please see the repository example notebooks and test cases for usage, as well as jpype documentation https://jpype.readthedocs.io/en/latest/index.html
Please see the [repository](https://gitlab.orekit.org/Petrush/orekit_jpype) example notebooks and test cases for usage, as well as jpype documentation https://jpype.readthedocs.io/en/latest/index.html
## Notes
The biggest difference between JCC and Jpype is that JCC is a static wrapping, creating c++ classes that are pre-defined when building the package, while JPype is dynamic and investigating the java machine on-the-fly.
# Installation
Each model has advantages and disadvantages.
* Requirements:
* JDK installed on your system (as Orekit is based on Java)
* Or alternatively [jdk4py](https://pypi.org/project/jdk4py/) can be used to provide JDK using pip, see usage instructions below
* Python >= 3.7 . Orekit Jpype is only tested for Python versions >= 3.9 because the CI pipeline depends on `jdk4py`, but Python 3.7 and 3.8 should work.
*`pip`
* Recommended: a `venv`
To install from PyPi:
```bash
pip install orekit-jpype
```
### JCC Pro's
- Can (probably) implement anything that is doable in Java in Python using the special classes (subclassing, interfaces)
- Stable when a compiled version has been created
- Well tested with orekit
- Good support for JCC but mainly one person who maintains and understand the code.
- Support for docstrings, reasonable rendering of javadoc
- Automatic adaptors enabling things like automatic translation between python datetime and AbsoluteDate.
- Well documented
- Medium hard to understand the wrapping code
- The wrapping is separate from the orekit part, maybe less issues with compiling (using conda)
- Easy to add user java code pieces as separate jars
- Direct mapping of numpy arrays to java arrays
### JPype Cons
- No subclassing of Java classes (Abstract classes in orekit cannot be used)
- Issues with restarting the JVM
- The unknown issues we don't know.
- Seems to have a slight performance hit (~10% increase in time in some very basic tests)
# usage
# Installation
See the example notebooks (`examples` folder) and the package `test` folder (only available in the source distribution or in the [git repo](https://gitlab.orekit.org/Petrush/orekit_jpype)) for examples.
if using mamba/conda:
## Usage difference from JCC based wrapper
mamba install -c conda-forge jpype1
### Casting
In the JCC version there is sometimes needed a .cast_() method to cast the object to the correct type. This is not needed in the JPype version.
### Implementation of Orekit interfaces
In the JCC version, the interfaces are implemented as special classes named PythonClassName that is then subclassed in Python. In the JPype version, the interfaces are implemented as python classes and marked with decorators, @JImplements and @JOverride, see https://jpype.readthedocs.io/en/latest/userguide.html#proxy-method-overloading
### Subclassing of Orekit abstract classes
In the JCC version of Orekit it is possible to subclass classes from the set of PythonClassName classes. This is not possible in the Jpype version of Orekit, which is limited to implementation of interfaces only. But instead it is possible to subclass abstract classes in Java, compile the JAR, and add the JAR to Orekit JPype, see section below.
The pip will also install the orekitdata package from the orekitdata git respotory.
You can add your own JARs to Orekit Jpype. For that, you can pass a list of classpaths via the argument `additional_classpaths` to the method `orekit_jpype.initVM`. An example can be found in the test case `tests-jvm/orekit_jpype_test_init_vm_with_extra_jars.py`.
### Java imports require the JVM to be started
# Development
As jpype loads the Java classes from JAR files on-the-fly, it cannot know which Java packages/classes exist before the JVM is started. Therefore the Java packages/classes can only be imported after the JVM is started.
The imports after the `orekit.initVM()` call will probably trigger PEP8 E402 warnings from `flake8` or `pylint`. As a workaround, you can add the following comment after the import to ignore these warnings:
# usage
See the example notebooks and the package test folder for examples.
```python
fromjava.utilimportArrayList# noqa: E402
```
### The JVM cannot be restarted
## Usage difference from JCC based wrapper
If you call the `jpype.shutdownJVM()` method, you won't be able to restart the JVM afterwards by calling `jpype.startJVM()` or `orekit_jpype.initVM()`. This is a known limitation of the JNI used by `jpype`: https://github.com/jpype-project/jpype/issues/959
### Casting
In the JCC version there is sometimes needed a .cast_() method to cast the object to the correct type. This is not needed in the JPype version.
### No JDK is provided
### Implementation of Orekit interfaces
In the JCC version, the interfaces are implemented as special classes named PythonClassName that is then subclassed in Python. In the JPype version, the interfaces are implemented as python classes and marked with decorators, @JImplements and @JOverride, see https://jpype.readthedocs.io/en/latest/userguide.html#proxy-method-overloading
Installing Orekit JCC via conda also installed an OpenJDK8. Instead, when installing Orekit Jpype via pip, no JDK is installed, so it's up to the user to install JDK on their machine.
### Subclassing of Orekit abstract classes
In the JCC version of Orekit it is possible to subclass classes from the set of PythonClassName classes. This is not possible in the Jpype version of Orekit, which is limited to implementation of interfaces only.
Another solution could be installing a JDK with pip thanks to the [jdk4py project](https://pypi.org/project/jdk4py/), and passing the path to the libjvm file to jpype by using the following syntax (taken from the test case `tests-jvm/orekit_jpype_test_init_vm_jdk4py.py`):
This will package a minimal executable containing orekit_jpype, orekitdata and run the test case `test/OrekitDataLoadOnlyLibTest.py` to test that everything works as expected.
TODO: include this test procedure in a CI pipeline.
# Notes on differences between the original JCC-based Orekit Python wrapper and this jpype-based wrapper
The biggest difference between JCC and Jpype is that JCC is a static wrapping, creating c++ classes that are pre-defined when building the package, while JPype is dynamic and investigating the java machine on-the-fly.
Each model has advantages and disadvantages.
### JCC Pro's
- Can (probably) implement anything that is doable in Java in Python using the special classes (subclassing, interfaces)
- Stable when a compiled version has been created
- Well tested with orekit
- Good support for JCC but mainly one person who maintains and understand the code.
- Easier to add custom java code to the system
### JCC Con's
- Special classes for subclassing.
- Special classes for interfaces
- Casting of types for classes with multiple inheritance
- Can be tricky to get it to compile (but when it does it is stable)
- Poor docstring support
- Very hard to understand the inner working of the wrapping code
- Need to recompile to add user java code pieces
### JPype Pro's
- Support for docstrings, reasonable rendering of javadoc
- Automatic adaptors enabling things like automatic translation between python datetime and AbsoluteDate.
- Well documented
- Medium hard to understand the wrapping code
- The wrapping is separate from the orekit part, maybe less issues with compiling (using conda)
- Easy to add user java code pieces as separate jars
- Direct mapping of numpy arrays to java arrays
### JPype Cons
- No subclassing of Java classes (Abstract classes in orekit cannot be used)
- Issues with restarting the JVM
- The unknown issues we don't know.
- Seems to have a slight performance hit (~10% increase in time in some very basic tests)
# Development
## Creating a venv
Using a Python virtual environment is highly recommended, do not install packages in your global python environment. To do so (in this example the venv will be located in the root of this git folder, but no worries, it is git-ignored):
```bash
python3 -m pip install virtualenv
python3 -m venv .orekitvenv
```
Activate the venv using:
```bash
source .orekitvenv/bin/activate
```
## Downloading JAR files and generating Python stubs
When a new version of one of the Java dependencies is available, the new JAR files must be downloaded and the stubs re-generated:
Downloading JARs requires having `maven` installed on your system.
And to generate stub files, the `stubgenj` package is required, it should be installed via pip together with the other dependencies of `orekit_jpype` (https://gitlab.cern.ch/scripting-tools/stubgenj)
* change the version of the corresponding artifact in `pom.xml`
* The following Python script will download new JARs and re-generate the stubs:
```bash
python3 dl_jars_and_render_stubs.py
```
## Checklist before uploading a new package version
* Open a merge request from your private branch into the `master` branch, containing:
* your changes, for instance newer versions of the Orekit JARs, changes to stubs, changes to test suites, etc.
* bump the package version in `pyproject.toml`.
* The package version should follow the Orekit versions: for example if based on Orekit `12.0.2`, the `orekit_jpype` package version should start with `12.0.2`, for instance `12.0.2.0`
* Follow the [Python version specifiers conventions](https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers)
* The merge request should be merged only if the CI pipeline passes. In particular, major releases of Orekit introduce breaking changes so it's likely that unit tests will fail and need to be modified
* After your branch is merged into the `master` branch, switch to the `master` branch and create a tag with the same name as the package version, for example `12.0.2.0`
* Stay in the `master` branch in the same tagged commit, and follow the instructions below to build and upload the wheel to PyPi
## Building wheel
* Make sure you have the latest version of PyPA’s [build](https://packaging.python.org/en/latest/key_projects/#build) installed:
An alternative implementation of orekit python wrapper based on Jpype and stubs generated by stubgenj. The interface is largely similar to the original JCC wrapped orekit version which is a more capable wrapper as it can subclass java classes, which Jpype cannot. The Jpype version is however easy to install, use and for most purposes sufficient.
Orekit (https://www.orekit.org/) is a low level library for space flight dynamics and is written in Java. The java API is located at: https://www.orekit.org/site-orekit-12.0.2/apidocs/index.html
# Installation
pip install orekit_jpype
The library also needs a dataset of varioud parameters, which can be installed with: