Accessing the Swiss Ephemeris

The Swiss Ephemeris(SE) is the standard library for astronomical calculations in astrological software. The SE is written in Ansi C and is easy to use by programs written in C or C++. For software in other languages, a dll is available but this of course is only usable in a Windows environment.

My intention is to rewrite the core of Enigma in Go and the user interface in Flutter/Dart. This means that I need to access the SE using code in Go. Three options are available:

  • rewriting the SE in Go. This would be an enormous task.
  • using the DLL. This would restrict the usage of Enigma to a Windows environment and I want to move to a cross-platform application.
  • accessing the C-code of the SE via a FFI (Foreign Function Interface) solution. Fortunately, such a solution exists for Go. It’s called cgo.

Using cgo, I can use the original c-code in my application and call C-functions from Go. This approach does require converting Go-variables into their C counterparts and it has some limitations on constructions with pointers. And there is a performance penalty: the conversion takes time and calling a C-function from Go is much slower than calling a C-function from C.

How does this work out in practice? I can already tell you that you would not be able to see any difference for a chart-calculation. But it could be an issue if a large sequence of calculations is required, e.g. for cycles.

I wanted to be sure about this, so I built a small wrapper for the SE, using cgo. The wrapper supports two functions: initializing the SE and calculating the position of a celestial body. I used code from the existing Go wrapper by Kaveh Shahbazian (https://github.com/workshop-depot/gosweph ) but needed to make some changes. I used this wrapper in a small program that calculates the position of Sun, Moon and Mercury for 1,000,000 consecutive days. I also wrote a program with the same functionality in C#, using the standard dll from the SE. The following table shows the time these calculations took, measured in milliseconds.

Calculation forMilliseconds when using Go and cgoMilliseconds when using C# and the SE dll
Sun10,3518,935
Moon10,4028,784
Mercury11,4509,623

The results show clearly that the combination of C# and the SE dll is faster but the differences are pretty small, a bit over 15%. In both cases we are talking about roughly 100,000 calculations per second. My conclusion: there is a small performance penalty when accessing the SE with Go but it is negligible.

I performed the tests on a PC with Windows 11, an AMD Ryzen 9 processor and 32 GB internal memory.

Dedicated Enigma modules

Enigma will support dedicated modules: programs to handle a specific research project but also usable for other projects. The code from the dedicated modules will often, but not always,  be added to the Enigma main program.

The first dedicated module is Enigma DedVM.  It supports a project by dutch researcher Vivian Muller into the astrological aspects of suicide.

You can download the compiled program and a user manual at radixpro.com. The source code is available at GitHub.

Back to Java

In august 2018 I decided to develop Enigma in Free Pascal. The main reason was that Oracle terminated the support for JavaFX. A company called Gluon would support it as an open source project, but I did not believe that JavaFX would last. Swing and SWT were no alternatives for me and using a web-interface in a native application had severe drawbacks.
I made some comparisons and Free Pascal was the clear winner. It was object oriented, open source and had an exceptional good way of handling the user interface. I knew the language from previous experiences, though that was some 15 years ago.
So I happily started coding. At first everything went well but as the application grew I experienced some stumble-blocks. The editor, with the beautiful name Lazarus, was good but it paled in comparison to intelliJ, the Java editor I was used to. Unit testing was possible but it missed some essential techniques, like mocking and calculating the test-coverage. And the way the source was handled, in units, files with mancy classes, was cumbersome. OK, I could have created small units but then I would have had problems defining the imports. I expect to be using at least 1000 classes after some further development, so this became a problem.
I found myself coding less and less because it was not so much fun anymore.
At the end of december 2019 the first version of Enigma was almost ready. It could calculate and draw a chart, work with configurations and used a database to store the essential information.
But I strongly felt the need for an alternative.
So I made a new comparison. Then I found that JavaFX was not dead. This was a big surprise for me. I expected it to slowly die after Oracle pulled the plug, but the open source community decided differently. JavaFX is alive and kicking and the support by Gluon works very well. Several new releases have been published while I was working with Free Pascal.
So I decided to return to Java. I was delighted with the efficiency of intelliJ and started coding. About 11 weeks later I almost completely rebuilt the codebase as writtin in Free Pascal. I am sure that future development will be fast as I’m using the perfect tools ànd coding is again fun for me.
I expect to have a first (beta) version, which will be 2020.1, available in May this year.
A new sourceset will then be posted at GitHub.

Some progress…

I knew that Free Pascal (FP) differed from the Java environment I used to work in before my recent retirement. But it still took me some efforts to adapt. The main problem I had was using automated testing. FP has excellent tools for unit testing, like FPC which I use. However, unit testing requires the testing of only one component and not any related components. To do so in a Java world, you would use mocks or fakes. FP has no viable solution for mocks, so I used fakes. That did not work out. Fakes require the use of interfaces (object interfaces, not just the unit interfaces). And good solutions use Dependency Injection (DI), which is not available in FP but you can mimic it using the Factory pattern. I ended up with too many components, interfaces and fakes, to be maintainable. So I skipped Fakes, I skipped object interfaces (at least as a default approach), I skipped factories, and I ended up with nice clean objects. In Java you would call it a POJO: Plain Old Java Object, in Pascal that would probably be a POPO 🙂  )
That means I cannot always use unit testing in the strict sense. And obviously, I need to test as much as possible to get early feedback on any error I make and to prevent bugs. I used Integration tests for all back-end functionality. I use FPC to implement these tests, so technically they start as a unit test but the functionality is different. The integration tests work with a greenfield for the database which is populated before a range of tests start. This approach appears to be useful.
Finishing release 0.6 will still take a few months but I hope to have it available, including documentation, user manual and all tests at the start of 2020.

Automated testing

Release 0.2 is finished and I started working on release 0.3. I will push the resulting code to GitLab so it will be available to anyone interested.
Release 0.3 will focus on refactoring the current application. Part of the refactoring will be the use of interfaces. Not the interface-parts of the units but interfaces for the objects. These interfaces will help in making the objects more loosely-coupled but also be a great help in automatically testing the code.
Free Pascal supports unit testing but it does not support mocking objects. There is a mock-tool but it is pretty old and not supported anymore. As an alternative, I will use Fake objects; in short, ‘Fakes’. A Fake implements the same interface as the original object but gives hardcoded answers instead of the real thing. If you write a unit test for an object that uses the results from another object, which again will have its own dependencies, you might end up testing a whole range of objects instead of the single object. That is where Fakes come in. They replace the objects that are not tested in the current unit test and make it possible to test just one class per unit test.

After I finished the code of release 0.3 you will be able to check the code, including the Fakes, yourself.