1{
2 lib,
3 stdenv,
4 fetchurl,
5 fetchFromGitHub,
6 fetchpatch,
7 fetchzip,
8 cmake,
9 lz4,
10 gfortran,
11 bzip2,
12 hdf5,
13 gsl,
14 unzip,
15 makeWrapper,
16 zlib,
17 meson,
18 ninja,
19 pandoc,
20 eigen,
21 pkg-config,
22 wrapGAppsHook3,
23 flex,
24 bison,
25 doxygen,
26 opencl-headers,
27 ncurses,
28 msgpack,
29 fftw,
30 zeromq,
31 ocl-icd,
32 gtk3,
33 gdk-pixbuf,
34 argp-standalone,
35 withGui ? true,
36 withBitshuffle ? true,
37}:
38
39let
40 libccp4 = stdenv.mkDerivation rec {
41 pname = "libccp4";
42 version = "8.0.0";
43 src = fetchurl {
44 url = "https://ftp.ccp4.ac.uk/opensource/libccp4-${version}.tar.gz";
45 hash = "sha256-y4E66GYSoIZjKd6rfO6W6sVz2BvlskA0HUD5rVMi/y0=";
46 };
47 nativeBuildInputs = [
48 meson
49 ninja
50 ];
51 buildInputs = [
52 hdf5
53 gsl
54 ];
55
56 configureFlags = [ "FFLAGS=-fallow-argument-mismatch" ];
57
58 # libccp4 tries to read syminfo.lib by looking at an environment variable, which hinders reproducibility.
59 # We hard-code this by providing a little patch and then passing the absolute path to syminfo.lib as a
60 # preprocessor flag.
61 env.NIX_CFLAGS_COMPILE = "-DNIX_PROVIDED_SYMOP_FILE=\"${placeholder "out"}/share/ccp4/syminfo.lib\"";
62
63 patches = [
64 ./libccp4-use-hardcoded-syminfo-lib.patch
65 ];
66
67 postPatch =
68 let
69 mesonPatch = fetchzip {
70 url = "https://wrapdb.mesonbuild.com/v2/libccp4c_8.0.0-1/get_patch#somefile.zip";
71 hash = "sha256-ohskfKh+972Pl56KtwAeWwHtAaAFNpCzz5vZBAI/vdU=";
72 };
73 in
74 ''
75 cp ${mesonPatch}/meson.build .
76 '';
77 };
78 # This is the statically-linked, pre-built binary of mosflm. Compiling it ourselves turns out to be very difficult
79 # since the build process is very hard-coded for a specific machine, architecture, and libraries.
80 mosflm =
81 let
82 version = "7.4.0";
83 src =
84 if stdenv.hostPlatform.isDarwin then
85 fetchurl {
86 url = "https://www.mrc-lmb.cam.ac.uk/mosflm/mosflm/ver${
87 builtins.replaceStrings [ "." ] [ "" ] version
88 }/pre-built/mosflm-osx-64-noX11.zip";
89 sha256 = "1da5wimv3kl8bccp49j69vh8gi28cn7axg59lrmb38s68c618h7j";
90 }
91 else
92 fetchurl {
93 url = "https://www.mrc-lmb.cam.ac.uk/mosflm/mosflm/ver${
94 builtins.replaceStrings [ "." ] [ "" ] version
95 }/pre-built/mosflm-linux-64-noX11.zip";
96 hash = "sha256:1f2qins5kaz5v6mkaclncqpirx3mlz177ywm13py9p6s9mk99g32";
97 };
98 mosflmBinary = if stdenv.hostPlatform.isDarwin then "bin/mosflm" else "mosflm-linux-64-noX11";
99 in
100 stdenv.mkDerivation {
101 pname = "mosflm";
102
103 inherit version src;
104
105 dontBuild = true;
106
107 nativeBuildInputs = [
108 unzip
109 makeWrapper
110 ];
111
112 sourceRoot = ".";
113
114 # mosflm statically links against its own libccp4, which as the syminfo.lib environment variable problem.
115 # Here, we circumvent it by creating a little wrapper script that calls mosflm after setting the SYMINFO variable.
116 installPhase = ''
117 mkdir -p $out/bin
118 cp ${mosflmBinary} $out/bin/mosflm-raw
119 makeWrapper $out/bin/mosflm-raw $out/bin/mosflm --set SYMINFO ${libccp4}/share/syminfo.lib --add-flags -n
120 '';
121 };
122
123 xgandalf = stdenv.mkDerivation rec {
124 pname = "xgandalf";
125 version = "c6c5003ff1086e8c0fb5313660b4f02f3a3aab7b";
126 src = fetchurl {
127 url = "https://gitlab.desy.de/thomas.white/xgandalf/-/archive/${version}/xgandalf-${version}.tar.gz";
128 hash = "sha256-/uZlBwAINSoYqgLQFTMz8rS1Rpadu79JkO6Bu/+Nx9E=";
129 };
130
131 nativeBuildInputs = [
132 meson
133 pkg-config
134 ninja
135 ];
136 buildInputs = [ eigen ];
137 };
138
139 pinkIndexer = stdenv.mkDerivation rec {
140 pname = "pinkindexer";
141 version = "15caa21191e27e989b750b29566e4379bc5cd21a";
142 src = fetchurl {
143 url = "https://gitlab.desy.de/thomas.white/${pname}/-/archive/${version}/${pname}-${version}.tar.gz";
144 hash = "sha256-v/SCJiHAV05Lc905y/dE8uBXlW+lLX9wau4XORYdbQg=";
145 };
146
147 nativeBuildInputs = [
148 meson
149 pkg-config
150 ninja
151 ];
152 buildInputs = [ eigen ];
153 };
154
155 fdip = stdenv.mkDerivation rec {
156 pname = "fdip";
157 version = "5628fedddd79323b4b26df9b85e9543d83286d4c";
158 src = fetchurl {
159 url = "https://gitlab.desy.de/thomas.white/fdip/-/archive/${version}/fdip-${version}.tar.gz";
160 hash = "sha256-EaihnW7p//ecgMn+KKlfmBeXrnAqs+HdhN+ovuSrtiQ=";
161 };
162
163 nativeBuildInputs = [
164 meson
165 ninja
166 pkg-config
167 ];
168 buildInputs = [ eigen ];
169 };
170
171 hdf5-external-filter-plugins = stdenv.mkDerivation rec {
172 pname = "HDF5-External-Filter-Plugins";
173 version = "0.1.0";
174 src = fetchFromGitHub {
175 owner = "nexusformat";
176 repo = pname;
177 rev = "49e3b65eca772bca77af13ba047d8b577673afba";
178 hash = "sha256-bEzfWdZuHmb0PDzCqy8Dey4tLtq+4coO0sT0GzqrTYI=";
179 };
180
181 patches = [
182 (fetchpatch {
183 url = "https://github.com/spanezz/HDF5-External-Filter-Plugins/commit/6b337fe36da97a3ef72354393687ce3386c0709d.patch";
184 hash = "sha256-wnBEdL/MjEyRHPwaVtuhzY+DW1AFeaUQUmIXh+JaRHo=";
185 })
186 ];
187
188 nativeBuildInputs = [ cmake ];
189 buildInputs = [
190 hdf5
191 lz4
192 bzip2
193 ];
194
195 cmakeFlags = [
196 "-DENABLE_BITSHUFFLE_PLUGIN=yes"
197 "-DENABLE_LZ4_PLUGIN=yes"
198 "-DENABLE_BZIP2_PLUGIN=yes"
199 ];
200 };
201
202 millepede-ii = stdenv.mkDerivation rec {
203 pname = "millepede-ii";
204 version = "04-13-06";
205 src = fetchurl {
206 url = "https://gitlab.desy.de/claus.kleinwort/millepede-ii/-/archive/V${version}/millepede-ii-V${version}.tar.gz";
207 hash = "sha256-aFoo8AGBsUEN2u3AmnSpTqJ6JeNV6j9vkAFTZ34I+sI=";
208 };
209
210 nativeBuildInputs = [ gfortran ];
211 buildInputs = [ zlib ];
212
213 makeFlags = [ "PREFIX=$(out)" ];
214 };
215in
216stdenv.mkDerivation rec {
217 pname = "crystfel";
218 version = "0.11.1";
219 src = fetchurl {
220 url = "https://www.desy.de/~twhite/crystfel/crystfel-${version}.tar.gz";
221 sha256 = "sha256-vZuN9dYnowySC/OX0EZB0mbhoBOyRiOWfX9d6sl1lKQ=";
222 };
223 nativeBuildInputs = [
224 meson
225 pkg-config
226 ninja
227 flex
228 bison
229 doxygen
230 opencl-headers
231 makeWrapper
232 ]
233 ++ lib.optionals withGui [ wrapGAppsHook3 ];
234 buildInputs = [
235 hdf5
236 gsl
237 ncurses
238 msgpack
239 fftw
240 fdip
241 zeromq
242 ocl-icd
243 libccp4
244 mosflm
245 pinkIndexer
246 xgandalf
247 pandoc
248 ]
249 ++ lib.optionals withGui [
250 gtk3
251 gdk-pixbuf
252 ]
253 ++ lib.optionals stdenv.hostPlatform.isDarwin [
254 argp-standalone
255 ]
256 ++ lib.optionals withBitshuffle [ hdf5-external-filter-plugins ];
257
258 patches = [
259 # on darwin at least, we need to link to a separate argp library;
260 # this patch adds a test for this and the necessary linker options
261 ./link-to-argp-standalone-if-needed.patch
262 ];
263
264 # CrystFEL calls mosflm by searching PATH for it. We could've create a wrapper script that sets the PATH, but
265 # we'd have to do that for every CrystFEL executable (indexamajig, crystfel, partialator). Better to just
266 # hard-code mosflm's path once.
267 postPatch = ''
268 sed -i -e 's#execlp("mosflm"#execl("${mosflm}/bin/mosflm"#' libcrystfel/src/indexers/mosflm.c;
269 '';
270
271 postInstall = lib.optionalString withBitshuffle ''
272 for file in $out/bin/*; do
273 wrapProgram $file \
274 --set HDF5_PLUGIN_PATH ${hdf5-external-filter-plugins}/lib/plugins \
275 --prefix PATH ":" ${lib.makeBinPath [ millepede-ii ]}
276 done
277 '';
278
279 meta = with lib; {
280 description = "Data processing for serial crystallography";
281 longDescription = ''
282 CrystFEL is a suite of programs for processing (and simulating) Bragg diffraction data from "serial crystallography" experiments, often (but not always) performed using an X-ray Free-Electron Laser. Compared to rotation data, some of the particular characteristics of such data which call for a specialised software suite are:
283
284 - The sliced, rather than integrated, measurement of intensity data. Many, if not all reflections are partially integrated.
285 - Many patterns (thousands) are required - high throughput is needed.
286 - The crystal orientations in each pattern are random and uncorrelated.
287 - Merging into lower symmetry point groups may require the resolution of indexing ambiguities.'';
288 homepage = "https://www.desy.de/~twhite/crystfel/";
289 changelog = "https://www.desy.de/~twhite/crystfel/changes.html";
290 downloadPage = "https://www.desy.de/~twhite/crystfel/download.html";
291 license = licenses.gpl3Plus;
292 maintainers = with maintainers; [ pmiddend ];
293 platforms = platforms.unix;
294 };
295
296}