Hi, James!

I have a few suggestions for your pylinac package. Three things I would like to be able to do.

Catphan 503

Hey Denis,
For the catphan, the distance between the air bubbles is a possible feature but I’m confused as to why. pylinac finds them already to determine the roll of the phantom; the distance between them wouldn’t be a problem. However, between the delrin and LDPE would be more difficult. Are the 50mm geometric holes not accurate enough? I’m confused as to why Elekta chooses this over the CatPhan recommendations. The longitudinal distance may be useful to verify the longitudinal integrity. I’ll look into that. For WL, this would indeed be helpful for those machines which don’t include that information in the DICOM metadata. I’ll work on this.

Thanks for the suggestions!

Hi James,

Yes, you’re right. You already have the feature to measure the air-air distance. I am actually using it already. Didn’t think before I wrote it as a suggestion.
As to why Elekta does it like this is beyond me. Maybe they just like larger distances.

Best regards,

Well, if you can give or point me to their manual and it’s definitely the “elekta way”, then I’ll consider adding it to help out the elekta users =)

hi Denis,
i m interested on wiston luts test carry out on elekta machine. could you share some information eg: field size, energy, MU, gantry, collimator and couch angle to carry out this test? thanks!


This is a very big question. It really depends on what you want to investigate :

To investigate the isocenter location, have first a look at this paper :

For an Elekta linac, it basically indicates to use the “kvFlexmapFunction”, which uses 4 gantry angles with two collimator sizes each.

You may find some small discrepancies between your own results (analyzed with pylinac) and the ones analyzed with XVI’s “flexmap analysis”. It is described in this paper :

And finally, you may want to improve your table rotation accuracy (rotation axis alignment with the isocenter). This paper is really cool :

I hacked my own analysis script using pylinac to adjust the table in order to achieve higher accuracy on non-coplanar fields.

Most of the tests are done at 6 MV but you may want to ensure correspondance with other energies :

Sorry, my links do not work. Here are the references in the same order :

Du, Weiliang, Jennifer L. Johnson, Wei Jiang, and Rajat J. Kudchadker. “On the Selection of Gantry and Collimator Angles for Isocenter Localization Using Winston-Lutz Tests.” Journal of Applied Clinical Medical Physics 17, no. 1 (January 8, 2016). doi:10.1120/jacmp.v17i1.5792.

Riis, Hans L., Lars N. Moltke, Sune J. Zimmermann, Martin A. Ebert, and Pejman Rowshanfarzad. “Investigation of the Accuracy of MV Radiation Isocentre Calculations in the Elekta Cone-Beam CT Software XVI.” Physics in Medicine and Biology 61, no. 11 (2016): N249. doi:10.1088/0031-9155/61/11/N249.

Nyflot, Matthew J., Ning Cao, Juergen Meyer, and Eric C. Ford. “Improved Accuracy for Noncoplanar Radiotherapy: An EPID-Based Method for Submillimeter Alignment of Linear Accelerator Table Rotation with MV Isocenter.” Journal of Applied Clinical Medical Physics 15, no. 2 (March 6, 2014).

Zhang, Yin, Kai Ding, Garth Cowan, Erik Tryggestad, Elwood Armour, and Ken Kang-Hsin Wang. “Alignment of Multiradiation Isocenters for Megavoltage Photon Beam.” Journal of Applied Clinical Medical Physics / American College of Medical Physics 16, no. 6 (2015): 5733.

Nyiri, Balazs J., Jason R. Smale, and Lee H. Gerig. “Two Self-Referencing Methods for the Measurement of Beam Spot Position.” Medical Physics 39, no. 12 (December 1, 2012): 7635–43. doi:10.1118/1.4766270.

Thank you for the detailed response. I’m gonna try to read some of these and also better acquaint myself with Elekta capabilities!

Hi there,

I am trying pylinac, this is my first post. First of all thanks for this awesome work!
I am an Elekta user and I came across this post which I found very useful. I have tried to analyze my flexmap images with pylinac but it does not work, it needs more images, the exact error is the following:
ValueError: Not enough images of the given type to identify the axis isocenter

my guess is that it needs more collimator images.
You can always add more collimator images but I am not sure if elekta flexmaps are analyzed correctly though. What I understand in pylinac documentation is that the three rotation axis are analyzed separately, so using opposing collimator angles for minimizing errors as Du et al. suggests (and Elekta flexmaps too) makes no sense, only 0º collimator angles will be analyzed. Is that correct?

Backproject the CAX for gantry images – Based on the vector of the BB to the field CAX and the gantry angle, a 3D line projection of the CAX is constructed. The BB is considered at the origin. Only images where the collimator and couch were at 0 are used for CAX projection lines.

If I am right, this could be solved overwriting collimator angles in dicom headers to 0º even if they are taken in some other positions.

By the way, Denis Brojan asked for a feature consisting in capturing angles from file names, I have a very basic and unpolished python script that does the trick, I run it selecting the folder that contains the dicom files named with keywords GANTRY COL and COUCH, ie: XXCOL45XXGANTRY87XXCOUCH23 → Collimator at 45º, gantry 87º and couch at 23º and add some specific tags for Elekta IVIEWGT:

import os,dicom
from PyQt5 import QtWidgets
dicom_path = QtWidgets.QFileDialog.getExistingDirectory(caption = ‘Selecciona la carpeta con los archivos DICOM’)
l = os.listdir(dicom_path)
for file in l:
edited = 0
d = dicom.read_file(os.path.join(dicom_path,file))
if ‘COUCH’ in file:
loc = file.find(‘COUCH’)
stop = 0
for n in range(len(file)-(loc+5)):
if file[loc + 5 + n].isdigit() and stop == 0:
couch_angle = float(file[(loc + 5):(loc + 5 + n +1)])
d.add_new([0x300A,0x122],‘DS’,couch_angle) #COUCH
stop =1
d.add_new([0x300A,0x122],‘DS’,0) #COUCH

if ‘COL’ in file:
loc = file.find(‘COL’)
stop = 0
for n in range(len(file)-(loc+3)):
if file[loc + 3 + n].isdigit() and stop == 0:
col_angle = float(file[(loc + 3):(loc + 3 + n +1)])
d.add_new([0x300A,0x120],‘DS’,col_angle) #COL
stop =1
d.add_new([0x300A,0x120],‘DS’,0) #COLL
if ‘GANTRY’ in file:
loc = file.find(‘GANTRY’)
stop = 0
for n in range(len(file)-(loc+6)):
if file[loc + 6 + n].isdigit() and stop == 0:
gantry_angle = float(file[(loc + 6):(loc + 6 + n +1)])
d.add_new([0x300A,0x11E],‘DS’,gantry_angle) #COUCH
print (gantry_angle)
stop =1
d.add_new([0x300A,0x11E],‘DS’,0) #COUCH
d.add_new([0x3002,0x011],‘DS’,[0.4,0.4])#Pixel Spacing

Thanks for the discussion and script! The good news is the next version of pylinac will be out soon and it will read axis values from the filename (this is where regular expressions shine). Additionally, the isocenter variation should no longer depend on the collimator being zero (I may need some test data though). The “not enough images” error should be resolved now; only a minimum of gantry images is required (i.e. it will plot fine if no coll or couch images are passed).

That s good news!
When it comes to the images I have analyzed, they also lack of SID and pixel spacing tags, I had to overwrite them with values 1600 and 0.4 respectively.

Thanks for your efforts.

Hi hoo yin Lim,

sorry for the late response. On the Versa HD linac which we use use for SBRT with none or minimal couch rotations, I do the Winston-Lutz test as follows: a sequence of eight images is acquired with the EPID in the following order: G180C0, G180C180, G270C180, G270C0, G0C0, G0C180, G90C180, G90C0. The field size iz either 2x2 or 5x5. Elekta’s ball bearing is used - it can be positioned either with the lasers, XVI or the light field. I prefer to do it with XVI because that way you get like an end-to-end results. Images are acquired with all available photon energies, that is 6X, 10X, 15X, 6FFF, 10FFF. Dose rate for flattened beams is on half of maximum, for the 6FFF it is one quater and for the 10 FFF one eights of maximum dose rate. Usually I give about 10 MU per image.
The reason I, at least currently, do not use couch rotations is because we do not do SRS of the head. Also we have problems with the results of the Winston-Lutz test as it is because of the gantry sag (about 1.3 mm).

This type of Winston-Lutz test is similiar what Elekta uses for positionion of the ball bearing during XVI isocenter calibration (flexmap), as Michael has explained. However, I am using pylinac to do the analysis. I use it to analyse single images and then I extract certain information that is useful to me. For example: I am interested what is the distance between the BB center and the field center at all gantry angles if I take out collimator asymmetry by averaging over opposite collimator angles. Furthermore, I calculate by how much the megavolt beams deviates from the ideal isocenter in the crossline direction (think about this one, it is very interesting that you can get such information from these eight images), what is the amount of gantry sag, what is the needed displacement of the BB to get it exactly into the megavolt isocenter and so on.

Michael pointed out important papers. Perhaps someone will find it interesting that Elekta’s software for positioning of the BB during flexmap calibration of XVI calculates the displacement of the ball bearing in a unique way, but only in the longitudinal directions. This is also mentioned in an articlethat Michael listed. The difference between Elekta’s calculation and pylinac amounts to about 0.3 mm. Which is what other software have given me as well.

Best regards,


Our center have Synergy linac with Agility heads with 6, 10 and 18 MV (+ electrons). No FFF.

We use 10x10 fields in our monthly QAs (we actually run the kvFlexmap sequence), but I agree that 2x2 and 5x5 fields are closer to SBRT.

Denis, do you know why we limit the dose rate ? Is it “beam spot” related or is it for better images on the flat panel ? Almost all of our SBRT case irradiate at the maximum dose rate (no FFF). To be more realistic, we should irradiate at the maximum dose rate (and use 2x2 fields). That only make sense if the dose rate can have an effect on the isocenter location.

The gantry sag is also ~ 1.2 mm. This is probably inevitable considering the overall weight of the linac !

As Denis guessed, we changed our couch iso adjustement method for Head SBRT (some fields use 90 degrees iso couch rotation !). The paper explains everything and is a “must have” for anyone interested in non-coplanar SBRT on Elekta.

Also, we do a “collimator Winston Lutz” : A sequence of 9 fields at Gantry 0, 10x10 field but various collimator angles. This gives an extra clue if the MLC/jaws are properly calibrated (offset calibration… your field sizes can still be wrong.).

In my opinion, this test can replace some of the Starshot tests… I have an ongoing argument with some of my collegues about that. My humble opinion is that Winston-Lutz is far superior to Starshots in many ways…


When I tried doing the Winston_lutz test for the FFF beams with the max dose rate, I would sometimes get a good image but sometimes a bad image. It’s like iViewGT cannot cope with large dose rates. Then I tried increasing the MUs, but couldn’t decide by how much - our detector is a later version which is not meant to be used with FFF beams, not even for portal dosimetry. So I lowered the dose rate instead. The image of the field with the BB inside was stable, but then I got unusual line artifact (some type of synchronization lines) in the exterior parts. Fortunately, I can cut them out from the image before I do the analysis.
I know that Elekta for some of it calibrations, like flexmap, uses lower dose rate when it comes taking MV images. Not really sure why, because I didn’t see any image problem with max dose rate for normal beams.

But, and I am quite happy that you pointed the focal spot position problem, in fact our little Versa HD has a problem with the stability of the beam focal spot. It turns out that the “position” of the 6 FFF beam can change by as much as 1.0 mm in the crossline direction when you go from really really low dose rote to max dose rate. I am expecting it to be fixed somehow, because I do not like it (fingers crossed). In any case what I have done is I have symmetrized this error so that the deviation of the beam is about ± 0.5 mm at all dose rates.

Well, Michael, it is rare that I would here someone else than myself say such things about the Winston-Lutz test. I couldn’t agree more with you.

Live long and prosper!