diff options
Diffstat (limited to 'src/pattern_sim.c')
-rw-r--r-- | src/pattern_sim.c | 1183 |
1 files changed, 0 insertions, 1183 deletions
diff --git a/src/pattern_sim.c b/src/pattern_sim.c deleted file mode 100644 index 9769a0d4..00000000 --- a/src/pattern_sim.c +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * pattern_sim.c - * - * Simulate diffraction patterns from small crystals - * - * Copyright © 2012-2021 Deutsches Elektronen-Synchrotron DESY, - * a research centre of the Helmholtz Association. - * - * Authors: - * 2009-2020 Thomas White <taw@physics.org> - * 2013-2014 Chun Hong Yoon <chun.hong.yoon@desy.de> - * 2014 Valerio Mariani - * 2013 Alexandra Tolstikova - * - * This file is part of CrystFEL. - * - * CrystFEL is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * CrystFEL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>. - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <getopt.h> -#include <hdf5.h> - -#include <image.h> -#include <cell.h> -#include <cell-utils.h> -#include <utils.h> -#include <peaks.h> -#include <symmetry.h> -#include <reflist.h> -#include <reflist-utils.h> -#include <stream.h> -#include <datatemplate.h> - -#include "diffraction.h" -#include "diffraction-gpu.h" -#include "pattern_sim.h" -#include "version.h" - - -enum spectrum_type { - SPECTRUM_TOPHAT, /**< A top hat distribution */ - SPECTRUM_GAUSSIAN, /**< A Gaussian distribution */ - SPECTRUM_SASE, /**< A simulated SASE spectrum */ - SPECTRUM_TWOCOLOUR, /**< A spectrum containing two peaks */ - SPECTRUM_FROMFILE /**< An arbitrary spectrum read from a file */ -}; - -static void show_help(const char *s) -{ - printf("Syntax: %s [options]\n\n", s); - printf( -"Simulate diffraction patterns from small crystals probed with femtosecond\n" -"pulses of X-rays from a free electron laser.\n" -"\n" -" -h, --help Display this help message.\n" -" --version Print CrystFEL version number and exit.\n" -"\n" -" -p, --pdb=<file> File from which to get the unit cell.\n" -" (The actual Bragg intensities come from the\n" -" intensities file)\n" -" --gpu Use the GPU to speed up the calculation.\n" -" --gpu-dev=<n> Use GPU device <n>. Omit this option to see the\n" -" available devices.\n" -" -g, --geometry=<file> Get detector geometry from file.\n" -" -n, --number=<N> Generate N images. Default 1.\n" -" --no-images Do not output any HDF5 files.\n" -" -o, --output=<filename> Output HDF5 filename. Default: sim.h5.\n" -" -r, --random-orientation Use randomly generated orientations.\n" -" --powder=<file> Write a summed pattern of all images simulated by\n" -" this invocation as the given filename.\n" -" -i, --intensities=<file> Specify file containing reflection intensities\n" -" (and phases) to use.\n" -" -y, --symmetry=<sym> The symmetry of the intensities file.\n" -" -t, --gradients=<method> Select method for calculation of shape transforms\n" -" --really-random Seed the random number generator with /dev/urandom.\n" -" --min-size=<s> Minimum crystal size in nm.\n" -" --max-size=<s> Maximum crystal size in nm.\n" -" --no-noise Do not calculate Poisson noise.\n" -" -s, --sample-spectrum=<N> Use N samples from spectrum. Default 3.\n" -" -x, --spectrum=<type> Type of spectrum to simulate.\n" -" --background=<N> Add N photons of Poisson background (default 0).\n" -" --template=<file> Take orientations from stream <file>.\n" -" --no-fringes Exclude the side maxima of Bragg peaks.\n" -" --flat Make Bragg peaks flat.\n" -" --sase-spike-width SASE spike width (standard deviation in m^-1)\n" -" Default 2e6 m^-1\n" -" --twocol-separation Separation between peaks in two-colour mode in m^-1\n" -" Default 8e6 m^-1\n" -" --nphotons Number of photons per X-ray pulse. Default 1e12.\n" -" --beam-radius Radius of beam in metres (default 1e-6).\n" -); -} - - -static void record_panel(struct detgeom_panel *p, float *dp, - int do_poisson, - gsl_rng *rng, double ph_per_e, double background, - double lambda, - int *n_neg1, int *n_inf1, int *n_nan1, - int *n_neg2, int *n_inf2, int *n_nan2, - double *max_tt) -{ - int fs, ss; - - for ( ss=0; ss<p->h; ss++ ) { - for ( fs=0; fs<p->w; fs++ ) { - - double counts; - double intensity, sa; - double pix_area, Lsq; - double xs, ys, rx, ry; - double dsq, proj_area; - float dval; - double twotheta; - - intensity = (double)dp[fs + p->w*ss]; - if ( isinf(intensity) ) (*n_inf1)++; - if ( intensity < 0.0 ) (*n_neg1)++; - if ( isnan(intensity) ) (*n_nan1)++; - - /* Area of one pixel */ - pix_area = pow(p->pixel_pitch, 2.0); - Lsq = pow(p->cnz*p->pixel_pitch, 2.0); - - /* Calculate distance from crystal to pixel */ - xs = fs*p->fsx + ss*p->ssx; - ys = ss*p->fsy + ss*p->ssy; - rx = (xs + p->cnx) * p->pixel_pitch; - ry = (ys + p->cny) * p->pixel_pitch; - dsq = pow(rx, 2.0) + pow(ry, 2.0); - twotheta = atan2(sqrt(dsq), p->cnz*p->pixel_pitch); - - /* Area of pixel as seen from crystal (approximate) */ - proj_area = pix_area * cos(twotheta); - - /* Projected area of pixel divided by distance squared */ - sa = proj_area / (dsq + Lsq); - - if ( do_poisson ) { - counts = poisson_noise(rng, intensity * ph_per_e * sa); - } else { - counts = intensity * ph_per_e * sa; - } - - /* Number of photons in pixel */ - dval = counts + poisson_noise(rng, background); - - /* Convert to ADU */ - dval *= p->adu_per_photon; - - /* Saturation */ - if ( dval > p->max_adu ) dval = p->max_adu; - - dp[fs + p->w*ss] = dval; - - /* Sanity checks */ - if ( isinf(dp[fs + p->w*ss]) ) n_inf2++; - if ( isnan(dp[fs + p->w*ss]) ) n_nan2++; - if ( dp[fs + p->w*ss] < 0.0 ) n_neg2++; - - if ( twotheta > *max_tt ) *max_tt = twotheta; - - } - } -} - - -void record_image(struct image *image, int do_poisson, double background, - gsl_rng *rng, double beam_radius, double nphotons) -{ - double total_energy, energy_density; - double ph_per_e; - double area; - double max_tt = 0.0; - int n_inf1 = 0; - int n_neg1 = 0; - int n_nan1 = 0; - int n_inf2 = 0; - int n_neg2 = 0; - int n_nan2 = 0; - int pn; - - /* How many photons are scattered per electron? */ - area = M_PI*pow(beam_radius, 2.0); - total_energy = nphotons * ph_lambda_to_en(image->lambda); - energy_density = total_energy / area; - ph_per_e = (nphotons /area) * pow(THOMSON_LENGTH, 2.0); - STATUS("Fluence = %8.2e photons, " - "Energy density = %5.3f kJ/cm^2, " - "Total energy = %5.3f microJ\n", - nphotons, energy_density/1e7, total_energy*1e6); - - for ( pn=0; pn<image->detgeom->n_panels; pn++ ) { - - record_panel(&image->detgeom->panels[pn], image->dp[pn], - do_poisson, rng, ph_per_e, background, - image->lambda, - &n_neg1, &n_inf1, &n_nan1, - &n_neg2, &n_inf2, &n_nan2, &max_tt); - } - - STATUS("Max 2theta = %.2f deg, min d = %.2f nm\n", - rad2deg(max_tt), (image->lambda/(2.0*sin(max_tt/2.0)))/1e-9); - - STATUS("Halve the d values to get the voxel size for a synthesis.\n"); - - if ( n_neg1 + n_inf1 + n_nan1 + n_neg2 + n_inf2 + n_nan2 ) { - ERROR("WARNING: The raw calculation produced %i negative" - " values, %i infinities and %i NaNs.\n", - n_neg1, n_inf1, n_nan1); - ERROR("WARNING: After processing, there were %i negative" - " values, %i infinities and %i NaNs.\n", - n_neg2, n_inf2, n_nan2); - } -} - - -static double *intensities_from_list(RefList *list, SymOpList *sym) -{ - Reflection *refl; - RefListIterator *iter; - double *out = new_arr_intensity(); - SymOpMask *m = new_symopmask(sym); - int neq = num_equivs(sym, NULL); - - for ( refl = first_refl(list, &iter); - refl != NULL; - refl = next_refl(refl, iter) ) { - - signed int h, k, l; - int eps; - double intensity = get_intensity(refl); - - get_indices(refl, &h, &k, &l); - special_position(sym, m, h, k, l); - eps = neq / num_equivs(sym, m); - - set_arr_intensity(out, h, k, l, intensity / eps); - - } - - return out; -} - - -static double *phases_from_list(RefList *list) -{ - Reflection *refl; - RefListIterator *iter; - double *out = new_arr_phase(); - - for ( refl = first_refl(list, &iter); - refl != NULL; - refl = next_refl(refl, iter) ) { - - signed int h, k, l; - double phase = get_phase(refl, NULL); - - get_indices(refl, &h, &k, &l); - - set_arr_phase(out, h, k, l, phase); - - } - - return out; - -} - - -static unsigned char *flags_from_list(RefList *list) -{ - Reflection *refl; - RefListIterator *iter; - unsigned char *out = new_arr_flag(); - - for ( refl = first_refl(list, &iter); - refl != NULL; - refl = next_refl(refl, iter) ) { - - signed int h, k, l; - - get_indices(refl, &h, &k, &l); - - set_arr_flag(out, h, k, l, 1); - - } - - return out; - -} - - -static struct quaternion read_quaternion() -{ - do { - - int r; - float w, x, y, z; - char line[1024]; - char *rval; - - printf("Please input quaternion: w x y z\n"); - rval = fgets(line, 1023, stdin); - if ( rval == NULL ) return invalid_quaternion(); - chomp(line); - - r = sscanf(line, "%f %f %f %f", &w, &x, &y, &z); - if ( r == 4 ) { - - struct quaternion quat; - - quat.w = w; - quat.x = x; - quat.y = y; - quat.z = z; - - return quat; - - } else { - ERROR("Invalid rotation '%s'\n", line); - } - - } while ( 1 ); -} - - -static int random_ncells(double len, double min_m, double max_m) -{ - int min_cells, max_cells, wid; - - min_cells = min_m / len; - max_cells = max_m / len; - wid = max_cells - min_cells; - - return wid*random()/RAND_MAX + min_cells; -} - - -static void add_metadata(const char *filename, - struct quaternion q, - UnitCell *cell) -{ - hid_t fh, gh, sh, dh; - herr_t r; - hsize_t size[1]; - float data[4]; - double asx, asy, asz, bsx, bsy, bsz, csx, csy, csz; - - cell_get_reciprocal(cell, &asx, &asy, &asz, - &bsx, &bsy, &bsz, - &csx, &csy, &csz); - - fh = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); - if ( fh < 0 ) { - ERROR("Failed to open file to add metadata.\n"); - return; - } - - gh = H5Gcreate2(fh, "pattern_sim", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - if ( gh < 0 ) { - ERROR("Failed to create metadata group.\n"); - H5Fclose(fh); - return; - } - - size[0] = 4; - sh = H5Screate_simple(1, size, NULL); - - dh = H5Dcreate2(gh, "quaternion", H5T_NATIVE_FLOAT, sh, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - if ( dh < 0 ) { - ERROR("Couldn't create dataset\n"); - H5Fclose(fh); - return; - } - - data[0] = q.w; - data[1] = q.x; - data[2] = q.y; - data[3] = q.z; - r = H5Dwrite(dh, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); - if ( r < 0 ) { - ERROR("Failed to write quaternion to file\n"); - } - H5Dclose(dh); - - size[0] = 3; - sh = H5Screate_simple(1, size, NULL); - - dh = H5Dcreate2(gh, "astar", H5T_NATIVE_FLOAT, sh, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - if ( dh < 0 ) { - ERROR("Couldn't create dataset\n"); - H5Fclose(fh); - return; - } - data[0] = asx; - data[1] = asy; - data[2] = asz; - r = H5Dwrite(dh, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); - if ( r < 0 ) { - ERROR("Failed to write astar to file.\n"); - } - H5Dclose(dh); - - dh = H5Dcreate2(gh, "bstar", H5T_NATIVE_FLOAT, sh, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - if ( dh < 0 ) { - ERROR("Couldn't create dataset\n"); - H5Fclose(fh); - return; - } - data[0] = bsx; - data[1] = bsy; - data[2] = bsz; - r = H5Dwrite(dh, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); - if ( r < 0 ) { - ERROR("Failed to write bstar to file.\n"); - } - H5Dclose(dh); - - dh = H5Dcreate2(gh, "cstar", H5T_NATIVE_FLOAT, sh, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - if ( dh < 0 ) { - ERROR("Couldn't create dataset\n"); - H5Fclose(fh); - return; - } - data[0] = csx; - data[1] = csy; - data[2] = csz; - r = H5Dwrite(dh, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); - if ( r < 0 ) { - ERROR("Failed to write cstar to file.\n"); - } - H5Dclose(dh); - - H5Gclose(gh); - H5Fclose(fh); -} - - -int main(int argc, char *argv[]) -{ - int argn; - struct image *image; - DataTemplate *dtempl; - struct gpu_context *gctx = NULL; - struct image *powder; - char *intfile = NULL; - double *intensities; - char *rval; - double *phases; - unsigned char *flags; - int config_randomquat = 0; - int config_noimages = 0; - int config_nonoise = 0; - int config_nosfac = 0; - int config_gpu = 0; - int config_random = 0; - char *powder_fn = NULL; - char *cell_filename = NULL; - char *grad_str = NULL; - char *outfile = NULL; - char *geometry = NULL; - char *spectrum_str = NULL; - char *spectrum_fn = NULL; - GradientMethod grad; - enum spectrum_type spectrum_type; - int ndone = 0; /* Number of simulations done (images or not) */ - int number = 1; /* Number used for filename of image */ - int n_images = 1; /* Generate one image by default */ - int done = 0; - UnitCell *input_cell; - struct quaternion orientation; - int gpu_dev = -1; - int random_size = 0; - double min_size = 0.0; - double max_size = 0.0; - char *sym_str = NULL; - SymOpList *sym; - int nsamples = 3; - gsl_rng *rng; - double background = 0.0; - char *template_file = NULL; - Stream *st = NULL; - int no_fringes = 0; - int flat = 0; - double nphotons = 1e12; - double beam_radius = 1e-6; /* metres */ - double sase_spike_width = 2e6; /* m^-1 */ - double twocol_sep = 8e6; /* m^-1 */ - - /* Long options */ - const struct option longopts[] = { - {"help", 0, NULL, 'h'}, - {"version", 0, NULL, 'v'}, - {"gpu", 0, &config_gpu, 1}, - {"beam", 1, NULL, 'b'}, - {"random-orientation", 0, NULL, 'r'}, - {"number", 1, NULL, 'n'}, - {"no-images", 0, &config_noimages, 1}, - {"no-noise", 0, &config_nonoise, 1}, - {"intensities", 1, NULL, 'i'}, - {"symmetry", 1, NULL, 'y'}, - {"powder", 1, NULL, 'w'}, - {"gradients", 1, NULL, 't'}, - {"pdb", 1, NULL, 'p'}, - {"output", 1, NULL, 'o'}, - {"geometry", 1, NULL, 'g'}, - {"sample-spectrum", 1, NULL, 's'}, - {"type-spectrum", 1, NULL, 'x'}, - {"spectrum", 1, NULL, 'x'}, - {"really-random", 0, &config_random, 1}, - {"no-fringes", 0, &no_fringes, 1}, - {"flat", 0, &flat, 1}, - - {"gpu-dev", 1, NULL, 2}, - {"min-size", 1, NULL, 3}, - {"max-size", 1, NULL, 4}, - {"background", 1, NULL, 5}, - {"template", 1, NULL, 6}, - {"beam-bandwidth", 1, NULL, 7}, - {"photon-energy", 1, NULL, 9}, - {"nphotons", 1, NULL, 10}, - {"beam-radius", 1, NULL, 11}, - {"spectrum-file", 1, NULL, 12}, - {"sase-spike-width", 1, NULL, 13}, - {"twocol-separation", 1, NULL, 14}, - - {0, 0, NULL, 0} - }; - - /* Short options */ - while ((argn = getopt_long(argc, argv, "hrn:i:t:p:o:g:y:s:x:vb:", - longopts, NULL)) != -1) { - - switch (argn) { - - case 'h' : - show_help(argv[0]); - return 0; - - case 'v' : - printf("CrystFEL: %s\n", - crystfel_version_string()); - printf("%s\n", - crystfel_licence_string()); - return 0; - - case 'b' : - ERROR("WARNING: This version of CrystFEL no longer " - "uses beam files. Please remove the beam file " - "from your pattern_sim command line.\n"); - return 1; - - case 'r' : - config_randomquat = 1; - break; - - case 'n' : - n_images = strtol(optarg, &rval, 10); - if ( *rval != '\0' ) { - ERROR("Invalid number of images.\n"); - return 1; - } - break; - - case 'i' : - intfile = strdup(optarg); - break; - - case 't' : - grad_str = strdup(optarg); - break; - - case 'p' : - cell_filename = strdup(optarg); - break; - - case 'o' : - outfile = strdup(optarg); - break; - - case 'w' : - powder_fn = strdup(optarg); - break; - - case 'g' : - geometry = strdup(optarg); - break; - - case 'y' : - sym_str = strdup(optarg); - break; - - case 's' : - nsamples = strtol(optarg, &rval, 10); - if ( *rval != '\0' ) { - ERROR("Invalid number of spectrum samples.\n"); - return 1; - } - break; - - case 'x' : - spectrum_str = strdup(optarg); - break; - - case 2 : - gpu_dev = atoi(optarg); - break; - - case 3 : - min_size = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid minimum size.\n"); - return 1; - } - min_size /= 1e9; - random_size++; - break; - - case 4 : - max_size = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid maximum size.\n"); - return 1; - } - max_size /= 1e9; - random_size++; - break; - - case 5 : - background = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid background level.\n"); - return 1; - } - break; - - case 6 : - template_file = strdup(optarg); - break; - - case 7 : - ERROR("--beam-bandwidth is no longer used.\n"); - ERROR("Set the bandwidth in the geometry file instead.\n"); - return 1; - - case 9 : - ERROR("--photon-energy is no longer used.\n"); - ERROR("Set the photon energy in the geometry file instead.\n"); - return 1; - - case 10 : - nphotons = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid number of photons.\n"); - return 1; - } - if ( nphotons < 0.0 ) { - ERROR("Number of photons must be positive.\n"); - return 1; - } - break; - - case 11 : - beam_radius = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid beam radius.\n"); - return 1; - } - if ( beam_radius < 0.0 ) { - ERROR("Beam radius must be positive.\n"); - return 1; - } - break; - - case 12 : - spectrum_fn = strdup(optarg); - break; - - case 13 : - sase_spike_width = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid SASE spike width.\n"); - return 1; - } - if ( beam_radius < 0.0 ) { - ERROR("SASE spike width must be positive.\n"); - return 1; - } - break; - - case 14 : - twocol_sep = strtod(optarg, &rval); - if ( *rval != '\0' ) { - ERROR("Invalid two colour separation.\n"); - return 1; - } - if ( beam_radius < 0.0 ) { - ERROR("Two-colour separation must be positive.\n"); - return 1; - } - break; - - case 0 : - break; - - case '?' : - break; - - default : - ERROR("Unhandled option '%c'\n", argn); - break; - - } - - } - - if ( random_size == 1 ) { - ERROR("You must specify both --min-size and --max-size.\n"); - return 1; - } - - if ( cell_filename == NULL ) { - cell_filename = strdup("molecule.pdb"); - } - - if ( outfile == NULL ) { - if ( n_images == 1 ) { - outfile = strdup("sim.h5"); - } else { - outfile = strdup("sim"); - } - } - - if ( template_file != NULL ) { - if ( config_randomquat ) { - ERROR("You cannot use -r and --template together.\n"); - return 1; - } - st = stream_open_for_read(template_file); - if ( st == NULL ) { - ERROR("Failed to open stream.\n"); - return 1; - } - free(template_file); - } - - if ( grad_str == NULL ) { - STATUS("You didn't specify a gradient calculation method, so" - " I'm using the 'mosaic' method, which is fastest.\n"); - grad = GRADIENT_MOSAIC; - } else if ( strcmp(grad_str, "mosaic") == 0 ) { - grad = GRADIENT_MOSAIC; - } else if ( strcmp(grad_str, "interpolate") == 0) { - grad = GRADIENT_INTERPOLATE; - } else if ( strcmp(grad_str, "phased") == 0) { - grad = GRADIENT_PHASED; - } else { - ERROR("Unrecognised gradient method '%s'\n", grad_str); - return 1; - } - free(grad_str); - - if ( config_gpu && (grad != GRADIENT_MOSAIC) ) { - ERROR("Only the mosaic method can be used for gradients when" - "calculating on the GPU.\n"); - return 1; - } - - if ( geometry == NULL ) { - ERROR("You need to specify a geometry file with --geometry\n"); - return 1; - } - dtempl = data_template_new_from_file(geometry); - if ( dtempl == NULL ) { - ERROR("Failed to read detector geometry from '%s'\n", - geometry); - return 1; - } - free(geometry); - - if ( spectrum_str == NULL ) { - STATUS("You didn't specify a spectrum type, so" - " I'm using a 'tophat' spectrum.\n"); - spectrum_type = SPECTRUM_TOPHAT; - } else if ( strcasecmp(spectrum_str, "tophat") == 0) { - spectrum_type = SPECTRUM_TOPHAT; - } else if ( strcasecmp(spectrum_str, "gaussian") == 0) { - spectrum_type = SPECTRUM_GAUSSIAN; - } else if ( strcasecmp(spectrum_str, "sase") == 0) { - spectrum_type = SPECTRUM_SASE; - } else if ( strcasecmp(spectrum_str, "twocolour") == 0 || - strcasecmp(spectrum_str, "twocolor") == 0 || - strcasecmp(spectrum_str, "twocolours") == 0 || - strcasecmp(spectrum_str, "twocolors") == 0) { - spectrum_type = SPECTRUM_TWOCOLOUR; - } else if ( strcasecmp(spectrum_str, "fromfile") == 0) { - spectrum_type = SPECTRUM_FROMFILE; - } else { - ERROR("Unrecognised spectrum type '%s'\n", spectrum_str); - return 1; - } - free(spectrum_str); - - /* Load unit cell */ - input_cell = load_cell_from_file(cell_filename); - if ( input_cell == NULL ) { - exit(1); - } - - if ( intfile == NULL ) { - - /* Gentle reminder */ - STATUS("You didn't specify the file containing the "); - STATUS("reflection intensities (with --intensities).\n"); - STATUS("I'll simulate a flat intensity distribution.\n"); - intensities = NULL; - phases = NULL; - flags = NULL; - - if ( sym_str == NULL ) sym_str = strdup("1"); - pointgroup_warning(sym_str); - sym = get_pointgroup(sym_str); - - } else { - - RefList *reflections; - char *sym_str_fromfile = NULL; - - reflections = read_reflections_2(intfile, &sym_str_fromfile); - if ( reflections == NULL ) { - ERROR("Problem reading input file %s\n", intfile); - return 1; - } - - /* If we don't have a point group yet, and if the file provides - * one, use the one from the file */ - if ( (sym_str == NULL) && (sym_str_fromfile != NULL) ) { - sym_str = sym_str_fromfile; - STATUS("Using symmetry from reflection file: %s\n", - sym_str); - } - - /* If we still don't have a point group, use "1" */ - if ( sym_str == NULL ) sym_str = strdup("1"); - - pointgroup_warning(sym_str); - sym = get_pointgroup(sym_str); - - if ( grad == GRADIENT_PHASED ) { - phases = phases_from_list(reflections); - } else { - phases = NULL; - } - intensities = intensities_from_list(reflections, sym); - flags = flags_from_list(reflections); - - /* Check that the intensities have the correct symmetry */ - if ( check_list_symmetry(reflections, sym) ) { - ERROR("The input reflection list does not appear to" - " have symmetry %s\n", symmetry_name(sym)); - if ( cell_get_lattice_type(input_cell) == L_MONOCLINIC ) - { - ERROR("You may need to specify the unique axis " - "in your point group. The default is " - "unique axis c.\n"); - ERROR("See 'man crystfel' for more details.\n"); - } - return 1; - } - - reflist_free(reflections); - - } - - rng = gsl_rng_alloc(gsl_rng_mt19937); - if ( config_random ) { - FILE *fh; - unsigned long int seed; - fh = fopen("/dev/urandom", "r"); - if ( fread(&seed, sizeof(seed), 1, fh) == 1 ) { - gsl_rng_set(rng, seed); - } else { - ERROR("Failed to seed random number generator\n"); - } - fclose(fh); - } - - image = image_create_for_simulation(dtempl); - powder = image_create_for_simulation(dtempl); - - /* Splurge a few useful numbers */ - STATUS("Simulation parameters:\n"); - STATUS(" Wavelength: %.5f A (photon energy %.2f eV)\n", - image->lambda*1e10, - ph_lambda_to_eV(image->lambda)); - STATUS(" Number of photons: %.0f (%.2f mJ)\n", - nphotons, eV_to_J(ph_lambda_to_eV(image->lambda))*nphotons*1e3); - STATUS(" Beam divergence: not simulated\n"); - STATUS(" Beam radius: %.2f microns\n", - beam_radius*1e6); - STATUS(" Background: %.2f photons\n", background); - - switch ( spectrum_type ) { - - case SPECTRUM_TOPHAT: - STATUS(" X-ray spectrum: top hat, " - "width %.5f %%\n", image->bw*100.0); - break; - - case SPECTRUM_GAUSSIAN: - STATUS(" X-ray spectrum: Gaussian, " - "bandwidth %.5f %%\n", image->bw*100.0); - break; - - case SPECTRUM_SASE: - STATUS(" X-ray spectrum: SASE, " - "bandwidth %.5f %%\n", image->bw*100.0); - break; - - case SPECTRUM_TWOCOLOUR: - STATUS(" X-ray spectrum: two colour, " - "bandwidth %.5f %%, separation %.5e m^-1\n", - image->bw*100.0, twocol_sep); - break; - - case SPECTRUM_FROMFILE: - STATUS(" X-ray spectrum: from %s\n", - spectrum_fn); - break; - } - if ( random_size ) { - STATUS(" Crystal size: random, between " - "%.2f and %.2f nm along each of a, b and c\n", - min_size*1e9, max_size*1e9); - } else { - STATUS(" Crystal size: 8 unit cells along " - "each of a, b and c\n"); - } - if ( intfile == NULL ) { - STATUS(" Full intensities: all equal\n"); - } else { - STATUS(" Full intensities: from %s (symmetry %s)\n", - intfile, sym_str); - } - do { - - int na, nb, nc; - double a, b, c, dis; - UnitCell *cell; - int err = 0; - int pi; - - /* Reset image data to zero for new pattern */ - for ( pi=0; pi<image->detgeom->n_panels; pi++ ) { - long j; - long np = image->detgeom->panels[pi].w - * image->detgeom->panels[pi].h; - for ( j=0; j<np; j++ ) { - image->dp[pi][j] = 0.0; - } - } - - if ( random_size ) { - - double alen, blen, clen, discard; - - cell_get_parameters(input_cell, &alen, &blen, &clen, - &discard, &discard, &discard); - - na = random_ncells(alen, min_size, max_size); - nb = random_ncells(blen, min_size, max_size); - nc = random_ncells(clen, min_size, max_size); - - } else { - - na = 8; - nb = 8; - nc = 8; - - } - - if ( st == NULL ) { - - if ( config_randomquat ) { - orientation = random_quaternion(rng); - } else { - orientation = read_quaternion(); - } - - STATUS("Orientation is %5.3f %5.3f %5.3f %5.3f\n", - orientation.w, orientation.x, - orientation.y, orientation.z); - - if ( !quaternion_valid(orientation) ) { - ERROR("Orientation modulus is not zero!\n"); - return 1; - } - - cell = cell_rotate(input_cell, orientation); - - } else { - - struct image *templ_image; - Crystal *cr; - - /* Get data from next chunk */ - templ_image = stream_read_chunk(st, 0); - if ( templ_image == NULL ) break; - if ( templ_image->n_crystals == 0 ) continue; - - cr = templ_image->crystals[0]; - cell = cell_new_from_cell(crystal_get_cell(cr)); - - if ( templ_image->n_crystals > 1 ) { - ERROR("Using the first crystal only.\n"); - } - - image_free(templ_image); - - } - - switch ( spectrum_type ) { - - case SPECTRUM_TOPHAT : - image->spectrum = spectrum_generate_tophat(image->lambda, - image->bw); - break; - - case SPECTRUM_GAUSSIAN : - image->spectrum = spectrum_generate_gaussian(image->lambda, - image->bw); - break; - - - case SPECTRUM_SASE : - image->spectrum = spectrum_generate_sase(image->lambda, - image->bw, - sase_spike_width, - rng); - break; - - case SPECTRUM_TWOCOLOUR : - image->spectrum = spectrum_generate_twocolour(image->lambda, - image->bw, - twocol_sep); - break; - - case SPECTRUM_FROMFILE : - image->spectrum = spectrum_load(spectrum_fn); - break; - - } - - cell_get_parameters(cell, &a, &b, &c, &dis, &dis, &dis); - STATUS("Particle size = %i x %i x %i" - " ( = %5.2f x %5.2f x %5.2f nm)\n", - na, nb, nc, na*a/1.0e-9, nb*b/1.0e-9, nc*c/1.0e-9); - - if ( config_gpu ) { - - if ( gctx == NULL ) { - gctx = setup_gpu(config_nosfac, - intensities, flags, sym_str, - gpu_dev); - } - err = get_diffraction_gpu(gctx, image, na, nb, nc, - cell, no_fringes, flat, - nsamples); - - } else { - get_diffraction(image, na, nb, nc, intensities, phases, - flags, cell, grad, sym, no_fringes, flat, - nsamples); - } - if ( err ) { - ERROR("Diffraction calculation failed.\n"); - done = 1; - goto skip; - } - - record_image(image, !config_nonoise, background, rng, - beam_radius, nphotons); - - if ( powder_fn != NULL ) { - - int pn; - - for ( pn=0; pn<image->detgeom->n_panels; pn++ ) { - - size_t w, i; - - w = image->detgeom->panels[pn].w - * image->detgeom->panels[pn].h; - - for ( i=0; i<w; i++ ) { - powder->dp[pn][i] += (double)image->dp[pn][i]; - } - - } - - if ( !(ndone % 10) ) { - image_write(powder, dtempl, powder_fn); - } - } - - if ( !config_noimages ) { - - char h5filename[1024]; - - if ( n_images != 1 ) { - snprintf(h5filename, 1023, "%s-%i.h5", - outfile, number); - } else { - strncpy(h5filename, outfile, 1023); - } - - number++; - - /* Write the output file */ - image_write(image, dtempl, h5filename); - - /* Add some pattern_sim-specific metadata */ - add_metadata(h5filename, orientation, cell); - - } - - cell_free(cell); - -skip: - ndone++; - - if ( n_images && (ndone >= n_images) ) done = 1; - - } while ( !done ); - - if ( powder_fn != NULL ) { - image_write(powder, dtempl, powder_fn); - } - - if ( gctx != NULL ) { - cleanup_gpu(gctx); - } - - image_free(image); - image_free(powder); - free(intfile); - cell_free(input_cell); - free(intensities); - free(outfile); - free(cell_filename); - free(sym_str); - free_symoplist(sym); - - gsl_rng_free(rng); - - return 0; -} |