Elekta Log Files

I’m in the process of improving and automating the QA in our clinic. We have an Elekta Infinity and Versa, both with the agility head, and I’m very interested in log file analysis. But I’ve got some big picture questions about this process.

How is your clinic pulling the log files from the machine? Is this automatic or a manual process?

At what frequency are you pulling log files? (daily? weekly? monthly?)

What exactly are you comparing the log files with?

How does physics actually review the results? What do you do with the data?

If you can help me with getting this process set up for our clinic, I wouldn’t mind doing some documentation and a write-up.

Thanks for putting this project out there for the community!

Hi @ekryck,

Welcome to the PyMedPhys community :slight_smile:.

That would be absolutely amazing. There would be many others out there in the community who would find that quite helpful.

Actually, I am no longer working at my previous clinic where I wrote this code. I have gone out on my own to create the startup Radiotherapy AI focused initially on radiotherapy autocontouring. Nevertheless, I’d be more than happy to answer your questions :slight_smile:

At a high level, PyMedPhys has an object called Delivery accessible at pymedphys.Delivery. Running the following commands gives you a bit of an idea what is achievable with this object:

In [1]: import pymedphys

In [2]: pymedphys.Delivery?
Init signature: pymedphys.Delivery(*args, **kwargs)
Docstring:      Delivery(monitor_units, gantry, collimator, mlc, jaw)
File:           ~/.asdf/installs/python/3.9.7/lib/python3.9/site-packages/pymedphys/_delivery.py
Type:           type

In [3]: [item for item in dir(pymedphys.Delivery) if not item.startswith('_')]

Essentially, it is an object that includes the MU, gantry angle, collimator angle, MLC positions and Jaw positions. This object is able to be created from a DICOM plan file, an Elekta Icom live logfile stream, an Elekta TRF backup logfile, the backend files from the Monaco planning system, or a Mosaiq database.

So essentially, any of these 5 sources can be utilised and converted into this common Delivery format. Once it is in this common format one can utilise the metersetmap function to create a sort of first order fluence calculation. These fluence calculations are then able to be compared with something like a gamma.

We then created an interactive GUI that pulls all of this functionality into a web front end for use day-to-day. Here is a video presentation where I detail the usage of this web frontend (at ~6 mins in):

Here are some GitHub issue where I discuss a bit more about the usage of this Delivery object:

The TRF files are being extracted from the weekly Linac backup files are using the pymedphys trf orchestrate command. Here is the bat file that we run every night using Windows Scheduler:

The Icom stream is collected live. It is using the pymedphys icom listen command. Here is the bat file that is converted into a service to listen to the Linac and save the Icom stream:

As mentioned above these are then compared utilising metersetmap. Some examples of using metersetmap can be seen at:


When PyMedPhys is installed you can start the GUI that we use by running the following command:

pymedphys gui

To customise how that GUI works, specific to your centre, you will need to create a config.toml file within the .pymedphys directory within your home drive. Here is the config.toml used at my previous centre:

Let me know if you need any more help :slight_smile:


@LipTeck_Chew, might you be able to reach out to @ekryck to give them a bit of a hand in getting started?

Hi @SimonBiggs, Hi @ekryck ,

We have managed to get the TRF files for two linacs (one VersaHD and one Infinity) out into a live folder and also group them into folders every biweekly.

We are also looking into automation. Our attempt to get information from MosaiqSQL has not been successful but the manual pymedphys is so far working ok for us.

There are a few challenges:

  1. Supplying PatientID information into the field description in Monaco plans so that the TRF files would have this information, removing the need to connect to MosaiqSQL.

  2. The Elekta TRF log files from time to time is affected and become " Z.trf" without field description information. Hence, even we can do (1), we still have to fix some of these Z files for automation. Fortunately, these files are still useful in manual pymedphys metersetmap using gui.

  3. Only VMAT and IMRT are working now in v.37.1. Field in field and 3D are not working yet.

  4. @SimonBiggs , could you show us in python command line how to compare a dicomRTPlan that has 3 TRF files instead of one TRF? Thank you.

  5. We hope it will be possible to reconstruct the TRF files back into a DicomRTPlan. This will enable a calculation of delivery plan in Monaco and then dose comparison!
    Is it possible with manual command line?

@ekryck , hope you have managed to get it up and going.


Hi @LipTeck_Chew,

Certainly :slight_smile:. Once you’ve converted the TRF file into a delivery object you can calculate the meterset map for each TRF file, and then add them all together. Here is how the PyMedPhys GUI does it:

Then, once the GUI has calculated the total meterset map for both the DICOM plan file and the TRF files it compares them using gamma:

Once it has the reference and evaluation metersetmap results, and the gamma determination it then plots everything using the following function:

Hi @SimonBiggs

Thank you for pointing out the codes in streamlit. Is it possible to run the pymedphys command line directly without going through the gui?

Meanwhile, I am thinking that there is no quick solution to workaround the missing field information in Z-TRF but to rely on RT or physicist who have performed the QA -plan/treatment plan delivery to copy the TRF files into manual patientID folder, say


with FPxxxxxxxx folders, each folder with a few TRF

Dicom Folder:


Completed Folder:



PDF Folder:


Then, we do a cron script to look into the dicom folder and TRF folder to match the PatientID (FPxxxxxxxx) so that,

it will then automatically run the MetersetMap and produce the PDF. Once completed, the cron script moves the dicom and trf folder to the respective done directories.

The current script runs in the gui. Could you enlighten me ? Thank you.


Have you looked into utilising the Icom logfiles? When using the Icom stream it has all of that information that I suspect you are after.

Unfortunately There aren’t any pymedphys CLI commands for metersetmap. Here are all of the TRF CLI commands:


You can however directly use Python to automate this. The following GitHub issue has some details of how to do it:


Hi @SimonBiggs

I’ve managed to use run a MetersetMap (MM) from python CML by using one of your previous notebook at https://notebook.community/SimonBiggs/SimonBiggs.github.io/icom
as base and added in some from the latest script at

It is working when the trf is a single file for plans with one beam. For plans with more than 1 beam with multiple trf, how do we properly create the delivery object?

fyi, we have

trf_directory = pathlib.Path(r'D:\mm\trf')
# trf_deliveries managed o list both v1.trf and v2.trf
trf_deliveries = list(trf_directory.glob(f'{patient_id}/*.trf'))

# the trf_path only pickup one trf, how do we fix this? How to generate tupple
# (d:\mm\trf\FP11111111\v1.trf,d:\mm\trf\FP11111111\v2.trf)

trf_path = list(trf_directory.glob(f'{patient_id}/*.trf'))[-1]

delivery_trf = pymedphys.Delivery.from_trf(trf_path)
metersetmap_trf = delivery_trf.metersetmap()

Thank you!

Hi @LipTeck_Chew :slight_smile:,

For plans with more than 1 beam with multiple trf, how do we properly create the delivery object?

The idea here is to actually just create a Delivery object for each of the TRF files, create a metersetmap result from each of those Delivery objects as you have in your code above, and then, you can add each metersetmap array together to get the final combined result. See the following:

Essentially, converting that code into using your approach above would look something like:

import numpy as np
import pymedphys

patient_id = 'FP11111111'

trf_directory = pathlib.Path(r'D:\mm\trf')
trf_paths = trf_directory.glob(f'{patient_id}/*.trf')

collected_meterset_maps = []
for path in trf_paths:
    delivery = pymedphys.Delivery.from_trf(path)
    meterset_map = delivery.metersetmap()


combined_meterset_map = np.sum(collected_meterset_maps, axis=0)

Thank you @SimonBiggs
It is finally working now! :joy:

I’ve managed to store and append the MetersetMap gamma results in a csv file after looping it through the trf folders and then make a box plot. I’ll see whether we can back track and batch process all previous recorded TRF. I can see the calculations is much faster without using the browser. The script will be useful to process all without someone clicking them through the gui.


Woo hoo!

There is a section with PyMedPhys where people can contribute what they have written to get PyMedPhys working at their site:

Might you be interested in putting some of the example code you’ve created over there?

:tada: :smiley:

Hi @SimonBiggs I’ve just uploaded. Has anyone converted the trfs back to a Dicom RTPlan dcm file compatible for Monaco?

Hi @LipTeck_Chew,

Here is a script I wrote back in 2019 that achieves this:

Here are some slides I presented on that project at ICCR in Canada back then:


Importantly, when you create a Delivery object there is a method called to_dicom which runs the following function:

It receives as input a template RT Plan file which it uses to then overwrite with the contents of the current delivery object. Delivery objects can be created from TRF files, so you’ve got the whole loop :slight_smile:.


First test:

Preparing to convert D:/mm/completed/recon/trf\22_02_04 05_28_54 Z V1_Arc1.trf
Loading log file
Converting log file to RT Plan DICOM
Traceback (most recent call last):
File “C:\Users\chewlipteck\Documents\Work\Computing\Python\Python Scripts\pylinac\python\trftodcm.py”, line 466, in
created_dicom = delivery_data.to_dicom(dicom_template)
File “c:\users\chewlipteck\env\lib\site-packages\pymedphys_dicom\delivery\core.py”, line 179, in to_dicom
template_gantry_angles = _pmp_rtplan.get_gantry_angles_from_dicom(
File “c:\users\chewlipteck\env\lib\site-packages\pymedphys_dicom\rtplan\core.py”, line 197, in get_gantry_angles_from_dicom
raise ValueError(
ValueError: Only a single gantry angle per beam is currently supported

Yeah, I never did end up making it work for VMAT