Docker, Fortran and C++
In the main section (How to Create a DAFNI Ready Model) we went over the steps needed to create a Dockerfile for the Fibonacci example, which is written in Python (an interpreted programming and scripting language). One of Docker's strengths is that it supports running models in many different languages, and in this section we will cover how you can dockerise models written in two compiled languages: C++ and Fortran 77.
Dockerising a Model Written in C++
For our first example of working with a compiled language, we are going to look at a model that has been written in C++, Pythia. Pythia is a particle physics model that is often used by collider experiments at CERN, and elsewhere, to simulate particle collisions at very high energies. We will use this model to demonstrate how we can dockerise a non-trivial model, and run it on DAFNI.
To get Pythia working on DAFNI the first step is to download the Dockerfile and config .yaml file from GitHub (from pythia_cpp ), and copy the files into a folder on your local machine. Note this will give us a README file, the Dockerfile and the model_definition (the config .yaml) file, but not the actual code which we will need to download separately.
pythia_cpp/
Dockerfile
model_definition.yaml
README.md
After doing this, we will download the C++ source code from the Pythia web page, which should be unzipped into our working folder (which contains the Dockerfile and yaml config file). At this point we are ready to go.
The most important things to note in the Dockerfile are the compilation stage, and the running stage. When we use the RUN command this is an instruction to Docker to run a command during dockerisation ('docker build') and this is the point where we ideally want to do the bulk (or all) of the code compilation. We will cover both stages in the notes below. It should be noted that the Dockerfile also contains several additional lines, which copy necessary files to the right folders for dockerisation.
The commands listed below will set the working directory (the equivalent of cd /home/pythia8308
), run a configure script and then compile the Pythia source code with the 'make' command (configure
& make
are the commands that we would normally use to compile Pythia on a linux/unix machine - note that your own model will probably have a different compilation setup!).
# Compile Pythia Libraries
WORKDIR /home/pythia8308
RUN ./configure
RUN make
The next part of the Dockerfile gives instructions for what happens when the Docker instance is bundled into a container and run. This part is as follows, and will be the section that runs when your model is run on DAFNI (or through the 'docker run' cmd).
# Compile examples & then run them (via the script, runmains)
WORKDIR /home/pythia8308/examples
ENTRYPOINT ./runmains --run="01 02 03"; cp main*.log /data/outputs/; cp main03plot.py /data/outputs/; cp out03plot*.dat /data/outputs/;
Again we move directories (this time to 'examples'), and then run the script runmains
, which in turn runs the Pythia test program. We also copy the output to /data/outputs/
so we can see it as output data when we run this model on DAFNI. Note how this is all carried out in one line, and that the commands are separated by semi-colons. This is very important as in Docker you can only run ENTRYPOINT
once - every command that happens at runtime will need to be on that one line (as in this example).
It should be noted it is also possible to save files inside the model you are running to
/data/outputs
. In the C++ example though we do it at the cmd level so we don't need to alter the code.An example of code which saves files internally can be found in the previous python Fibonacci Model, which contains the following lines.
# Output the results to a file output_folder.mkdir(parents=True, exist_ok=True) output_file = output_folder.joinpath("sequence.json") output_file.write_text(json.dumps({"sequence": sequence}))
Though we haven't actually declared any input variables in the given .yaml file, if we had, we could access these variables in the model code itself using environment variables (in the same way as the Fibonacci example). These can be accessed in C++ using the C standard library.
For example, if we defined NEVENTS in our config .yaml file (and NEVENTS is expected to be an integer) we can access this in our model code with the following lines.
#include <cstdlib>
char* env_variable = "NEVENTS";
int var1;
var1 = getenv(env_variable);
Once you have all the files in your folder, you can dockerise this model with:
docker build -t pythia-cpp .
docker save -o pythia-cpp.tar pythia-cpp
You can then use gzip to create pythia-cpp.tar.gz
. This file can be then uploaded to DAFNI with the .yaml config file (see How to Upload a Model). nb. Be careful to use gzip, and not the standard windows zip format if you are on a Windows machine.
Dockerising a Model Written in f77 (Fortran)
We will also use an example of an older version of the same model (Pythia) that was written in f77, to demonstrate how to work with Fortran models. You can download the Dockerfile and .yaml config from GitHub. You can get the Fortran code we will need from the Pythia web-site; the main Pythia code is in pythia6428.f and the test example we will use is main63.f.
In many ways how we dockerise the f77 model is similar to the steps in the C++ example; there is one major difference though (apart from the language!) and that is that the compilation stage is handled directly here, rather than through a Makefile (again we use 'RUN' - we only want compilation to occur at the 'docker build' stage). It's a fairly straightforward process as we only have two Fortran files (one is an example, the other contains the main code).
RUN f77 -c -o pythia6428.o pythia6428.f
RUN f77 main63.f pythia6428.o
The line in the Dockerfile that is used to run the executable is as below (note the executable we get from running f77 the second time is called a.out
by default).
CMD ./a.out > log.txt; cp log.txt /data/outputs/
Again we copy the output to /data/outputs
(for use in DAFNI).
As in C++ it is possible to access environment variables in Fortran. This can be done using code like that shown below.
C...Read-in the evironment variable NEVE (which is set in the yaml file).
CALL getenv('NEVE',NEVE)
C...Main parameters of run: c.m. energy and number of events.
ECM=91.2D0
NEV=NEVE
As before, once you have all the files in your folder, you can dockerise this model with:
docker build -t pythia-f77 .
docker save -o pythia-f77.tar pythia-f77