diff --git a/src/geomtools/detector/crystfel_frm.py b/src/geomtools/detector/crystfel_frm.py
index 77d94d6504caf2e3db6a267fef76b2a759fee0c7..6ae4e1b2dc16222c1ed9527dd36b783b187e86db 100644
--- a/src/geomtools/detector/crystfel_frm.py
+++ b/src/geomtools/detector/crystfel_frm.py
@@ -1,10 +1,9 @@
+import h5py
 import numpy as np
 import pandas as pd
-
 from cfelpyutils.geometry import load_crystfel_geometry
 from natsort import natsorted
 
-
 HEADER_TEMPLATE = """\
 ; {detector} geometry file written by geomtools
 ; You may need to edit this file to add:
@@ -39,7 +38,7 @@ def _format_vec(vec):
     ])
 
 
-def write_crystfel_geom(file, panels, beam, rigid_groups):
+def write_crystfel_geom(file, panels, beam, rigid_groups, mask=None):
     """Writes geometry in CrystFEL format in file."""
     # header
     clen = panels.clen[0]
@@ -48,11 +47,19 @@ def write_crystfel_geom(file, panels, beam, rigid_groups):
         panels.data[0] if panels.data[0]
         else "/entry_1/data_1/data"
     )
-    mask = panels['mask'][0]
-    if mask:
-        paths['mask'] = mask
+    if mask is None:
+        if 'mask' in panels.colums:
+            paths['mask'] = panels['mask'][0]
+        else:
+            paths['mask'] = "/entry_1/instrument_1/detector_1/mask"
+        if 'mask_file' in panels.columns:
+            paths['mask_file'] = panels.mask_file[0]
     else:
-        paths['mask'] = "/entry_1/instrument_1/detector_1/mask"
+        paths['mask'] = mask['path']
+        paths['mask_file'] = mask['file']
+        paths['mask_good'] = hex(mask['good'])
+        paths['mask_bad'] = hex(mask['bad'])
+
     path_str = '\n'.join('{} = {} ;'.format(i, j) for i, j in paths.items())
     header = HEADER_TEMPLATE.format(
         detector="AGIPD1M", resolution=1/200e-6, frame_dim=0,
@@ -139,4 +146,22 @@ def read_crystfel_geom(filename, indexes=dict()):
     for column, dimno in indexes.items():
         panels[column] = panels.dim_structure.apply(lambda x: x[dimno])
 
-    return panels, geom.beam
+    if "mask_file" in panels.columns and panels.mask_file[0]:
+        mask_file = panels.mask_file[0]
+    else:
+        mask_file = None
+    if "mask" in panels.columns and panels['mask'][0]:
+        mask_path = panels['mask'][0]
+    else:
+        mask_path = "/entry_1/data_1/mask"
+    mask_goodbits = geom.detector.get('mask_good', 0)
+    mask_badbits = geom.detector.get('mask_bad', 0)
+    if mask_file:
+        with h5py.File(mask_file, "r") as f:
+            mask = f[mask_path][:]
+            mask = (
+                (np.bitwise_and(mask, mask_goodbits) != mask_goodbits) |
+                (np.bitwise_and(mask, mask_badbits) != 0)
+            )
+
+    return panels, geom.beam, mask
diff --git a/src/geomtools/sfx/optimiser.py b/src/geomtools/sfx/optimiser.py
index 7802380f0cdb87a64f4aef8cb74c3e8e80ed3517..3bf6d2361662f50ba5c8ef22c2ce87606f1d82c8 100644
--- a/src/geomtools/sfx/optimiser.py
+++ b/src/geomtools/sfx/optimiser.py
@@ -32,7 +32,7 @@ def refine():
     temp_geom_file.write(geom_file.read())
     geom_file.seek(0)
 
-    panels, beam = read_crystfel_geom(
+    panels, beam, mask = read_crystfel_geom(
         temp_geom_file.name, indexes={'modno': 1})
 
     temp_geom_file.close()
@@ -45,15 +45,23 @@ def refine():
 
     px = badpixels_mask(pe, panels)
     shape = get_detector_shape(panels)
-    msk = pixels_to_image(shape, px)
+    badpx = pixels_to_image(shape, px)
 
     geom_fn = args.output
-    with open(geom_fn.absolute(), "w") as f:
-        write_crystfel_geom(f, panels_new, beam, ["modules", "quads"])
+
+    mask_path = "/entry_1/data_1/mask"
+    mask_fn = geom_fn.parent / (geom_fn.stem + "_hotpixels.h5")
+    with h5py.File(mask_fn, "w") as f:
+        f[mask_path] = badpx.astype("u2")
 
     mask_fn = geom_fn.parent / (geom_fn.stem + "_mask.h5")
     with h5py.File(mask_fn, "w") as f:
-        f["/entry_1/data_1/mask"] = msk.astype("u2")
+        f[mask_path] = (mask | badpx).astype("u2")
+
+    mask = dict(path=mask_path, file=mask_fn.resolve(), good=0, bad=0xffff)
+
+    with open(geom_fn.absolute(), "w") as f:
+        write_crystfel_geom(f, panels_new, beam, ["modules", "quads"], mask)
 
 
 if __name__ == "__main__":
diff --git a/src/geomtools/sfx/report.ipynb b/src/geomtools/sfx/report.ipynb
index a266245165955dba25b1c2c9f13289fbac497f88..294804339c4fcc836a6309c2c96fe0b7e3cff4d5 100644
--- a/src/geomtools/sfx/report.ipynb
+++ b/src/geomtools/sfx/report.ipynb
@@ -52,7 +52,7 @@
     "propno = int(xwiz_conf['data']['proposal'])\n",
     "runs = eval(xwiz_conf['data']['runs'])\n",
     "\n",
-    "panels, beam = read_crystfel_geom(geometry_file, indexes={'modno': 1})\n",
+    "panels, beam, mask = read_crystfel_geom(geometry_file, indexes={'modno': 1})\n",
     "\n",
     "panel_columns = panels.columns.tolist() + ['panel']\n",
     "if connected_groups not in panel_columns:\n",