Ejemplo n.º 1
0
static void perturb(const long dims[2], complex float* vecs, float amt)
{
	complex float* noise = md_alloc(2, dims, CFL_SIZE);

	md_gaussian_rand(2, dims, noise);

	for (long j = 0; j < dims[1]; j++) {

		float nrm = md_znorm(1, dims, noise + j * dims[0]);
		complex float val = amt / nrm;
		md_zsmul(1, dims, noise + j * dims[0], noise + j * dims[0], val);
	}

	md_zadd(2, dims, vecs, vecs, noise);

	for (long j = 0; j < dims[1]; j++) {

		float nrm = md_znorm(1, dims, vecs + j * dims[0]);
		complex float val = 1 / nrm;
		md_zsmul(1, dims, vecs + j * dims[0], vecs + j * dims[0], val);
	}

	md_free(noise);
}
Ejemplo n.º 2
0
static double bench_norm(int s, long scale)
{
	long dims[DIMS] = { 256 * scale, 256 * scale, 1, 16, 1, 1, 1, 1 };
#if 0
	complex float* x = md_alloc_gpu(DIMS, dims, CFL_SIZE);
	complex float* y = md_alloc_gpu(DIMS, dims, CFL_SIZE);
#else
	complex float* x = md_alloc(DIMS, dims, CFL_SIZE);
	complex float* y = md_alloc(DIMS, dims, CFL_SIZE);
#endif
	
	md_gaussian_rand(DIMS, dims, x);
	md_gaussian_rand(DIMS, dims, y);

	double tic = timestamp();

	switch (s) {
	case 0:
		md_zscalar(DIMS, dims, x, y);
		break;
	case 1:
		md_zscalar_real(DIMS, dims, x, y);
		break;
	case 2:
		md_znorm(DIMS, dims, x);
		break;
	case 3:
		md_z1norm(DIMS, dims, x);
		break;
	}

	double toc = timestamp();

	md_free(x);
	md_free(y);
	
	return toc - tic;
}
Ejemplo n.º 3
0
int main_bpsense(int argc, char* argv[])
{
	// -----------------------------------------------------------
	// set up conf and option parser
	
	struct bpsense_conf conf = bpsense_defaults;
	struct iter_admm_conf iconf = iter_admm_defaults;
	conf.iconf = &iconf;
	conf.iconf->rho = 10; // more sensibile default

	bool usegpu = false;
	const char* psf = NULL;
	const char* image_truth_fname = NULL;
	bool im_truth = false;
	bool use_tvnorm = false;

	double start_time = timestamp();


	const struct opt_s opts[] = {

		OPT_FLOAT('e', &conf.eps, "eps", "data consistency error"),
		OPT_FLOAT('r', &conf.lambda, "lambda", "l2 regularization parameter"),
		OPT_FLOAT('u', &conf.iconf->rho, "rho", "ADMM penalty parameter"),
		OPT_SET('c', &conf.rvc, "real-value constraint"),
		OPT_SET('t', &use_tvnorm, "use TV norm"),
		OPT_STRING('T', &image_truth_fname, "file", "compare to truth image"),
		OPT_UINT('i', &conf.iconf->maxiter, "iter", "max. iterations"),
		OPT_SET('g', &usegpu, "(use gpu)"),
		OPT_STRING('p', &psf, "file", "point-spread function"),
	};

	cmdline(&argc, argv, 3, 3, usage_str, help_str, ARRAY_SIZE(opts), opts);

	if (NULL != image_truth_fname)
		im_truth = true;


	// -----------------------------------------------------------
	// load data and print some info about the recon

	int N = DIMS;

	long dims[N];
	long dims1[N];
	long img_dims[N];
	long ksp_dims[N];

	complex float* kspace_data = load_cfl(argv[1], N, ksp_dims);
	complex float* sens_maps = load_cfl(argv[2], N, dims);

	for (int i = 0; i < 4; i++)	// sizes2[4] may be > 1
		if (ksp_dims[i] != dims[i])
			error("Dimensions of kspace and sensitivities do not match!\n");

	assert(1 == ksp_dims[MAPS_DIM]);


	(usegpu ? num_init_gpu : num_init)();

	if (dims[MAPS_DIM] > 1) 
		debug_printf(DP_INFO, "%ld maps.\nESPIRiT reconstruction.\n", dims[4]);

	if (conf.lambda > 0.)
		debug_printf(DP_INFO, "l2 regularization: %f\n", conf.lambda);

	if (use_tvnorm)
		debug_printf(DP_INFO, "use Total Variation\n");
	else
		debug_printf(DP_INFO, "use Wavelets\n");

	if (im_truth)
		debug_printf(DP_INFO, "Compare to truth\n");

	md_select_dims(N, ~(COIL_FLAG | MAPS_FLAG), dims1, dims);
	md_select_dims(N, ~COIL_FLAG, img_dims, dims);


	// -----------------------------------------------------------
	// initialize sampling pattern

	complex float* pattern = NULL;
	long pat_dims[N];

	if (NULL != psf) {

		pattern = load_cfl(psf, N, pat_dims);

		// FIXME: check compatibility
	} else {

		pattern = md_alloc(N, dims1, CFL_SIZE);
		estimate_pattern(N, ksp_dims, COIL_DIM, pattern, kspace_data);
	}

	
	// -----------------------------------------------------------
	// print some statistics

	size_t T = md_calc_size(N, dims1);
	long samples = (long)pow(md_znorm(N, dims1, pattern), 2.);
	debug_printf(DP_INFO, "Size: %ld Samples: %ld Acc: %.2f\n", T, samples, (float)T/(float)samples); 


	// -----------------------------------------------------------
	// fftmod to un-center data
	
	fftmod(N, ksp_dims, FFT_FLAGS, kspace_data, kspace_data);
	fftmod(N, dims, FFT_FLAGS, sens_maps, sens_maps);


	// -----------------------------------------------------------
	// apply scaling

	float scaling = estimate_scaling(ksp_dims, NULL, kspace_data);

	debug_printf(DP_INFO, "Scaling: %f\n", scaling);

	if (scaling != 0.)
		md_zsmul(N, ksp_dims, kspace_data, kspace_data, 1. / scaling);


	// -----------------------------------------------------------
	// create l1 prox operator and transform

	long minsize[DIMS] = { [0 ... DIMS - 1] = 1 };
	minsize[0] = MIN(img_dims[0], 16);
	minsize[1] = MIN(img_dims[1], 16);
	minsize[2] = MIN(img_dims[2], 16);

	const struct linop_s* l1op = NULL;
	const struct operator_p_s* l1prox = NULL;

	if (use_tvnorm) {

		l1op = grad_init(DIMS, img_dims, FFT_FLAGS);
		l1prox = prox_thresh_create(DIMS + 1, linop_codomain(l1op)->dims, 1., 0u, usegpu);
		conf.l1op_obj = l1op;

	} else {

		bool randshift = true;
		l1op = linop_identity_create(DIMS, img_dims);
		conf.l1op_obj = wavelet_create(DIMS, img_dims, FFT_FLAGS, minsize, false, usegpu);
		l1prox = prox_wavethresh_create(DIMS, img_dims, FFT_FLAGS, minsize, 1., randshift, usegpu);
	}


	// -----------------------------------------------------------
	// create image and load truth image
	
	complex float* image = create_cfl(argv[3], N, img_dims);
	
	md_clear(N, img_dims, image, CFL_SIZE);

	long img_truth_dims[DIMS];
	complex float* image_truth = NULL;

	if (im_truth)
		image_truth = load_cfl(image_truth_fname, DIMS, img_truth_dims);

	// -----------------------------------------------------------
	// call recon
	
	if (usegpu) 
#ifdef USE_CUDA
		bpsense_recon_gpu(&conf, dims, image, sens_maps, dims1, pattern, l1op, l1prox, ksp_dims, kspace_data, image_truth);
#else
		assert(0);
#endif
	else
Ejemplo n.º 4
0
Archivo: nlinv.c Proyecto: nckz/bart
int main_nlinv(int argc, char* argv[])
{
    int iter = 8;
    float l1 = -1.;
    bool waterfat = false;
    bool rvc = false;
    bool normalize = true;
    float restrict_fov = -1.;
    float csh[3] = { 0., 0., 0. };
    bool usegpu = false;
    const char* psf = NULL;

    const struct opt_s opts[] = {

        { 'l', true, opt_float, &l1, NULL },
        { 'i', true, opt_int, &iter, NULL },
        { 'c', false, opt_set, &rvc, NULL },
        { 'N', false, opt_clear, &normalize, NULL },
        { 'f', true, opt_float, &restrict_fov, NULL },
        { 'p', true, opt_string, &psf, NULL },
        { 'g', false, opt_set, &usegpu, NULL },
    };

    cmdline(&argc, argv, 2, 3, usage_str, help_str, ARRAY_SIZE(opts), opts);

    num_init();

    assert(iter > 0);


    long ksp_dims[DIMS];
    complex float* kspace_data = load_cfl(argv[1], DIMS, ksp_dims);

    long dims[DIMS];
    md_copy_dims(DIMS, dims, ksp_dims);

    if (waterfat)
        dims[CSHIFT_DIM] = 2;

    long img_dims[DIMS];
    md_select_dims(DIMS, FFT_FLAGS|CSHIFT_FLAG, img_dims, dims);

    long img_strs[DIMS];
    md_calc_strides(DIMS, img_strs, img_dims, CFL_SIZE);


    complex float* image = create_cfl(argv[2], DIMS, img_dims);

    long msk_dims[DIMS];
    md_select_dims(DIMS, FFT_FLAGS, msk_dims, dims);

    long msk_strs[DIMS];
    md_calc_strides(DIMS, msk_strs, msk_dims, CFL_SIZE);

    complex float* mask;
    complex float* norm = md_alloc(DIMS, msk_dims, CFL_SIZE);
    complex float* sens;

    if (4 == argc) {

        sens = create_cfl(argv[3], DIMS, ksp_dims);

    } else {

        sens = md_alloc(DIMS, ksp_dims, CFL_SIZE);
    }


    complex float* pattern = NULL;
    long pat_dims[DIMS];

    if (NULL != psf) {

        pattern = load_cfl(psf, DIMS, pat_dims);

        // FIXME: check compatibility
    } else {

        pattern = md_alloc(DIMS, img_dims, CFL_SIZE);
        estimate_pattern(DIMS, ksp_dims, COIL_DIM, pattern, kspace_data);
    }


    if (waterfat) {

        size_t size = md_calc_size(DIMS, msk_dims);
        md_copy(DIMS, msk_dims, pattern + size, pattern, CFL_SIZE);

        long shift_dims[DIMS];
        md_select_dims(DIMS, FFT_FLAGS, shift_dims, msk_dims);

        long shift_strs[DIMS];
        md_calc_strides(DIMS, shift_strs, shift_dims, CFL_SIZE);

        complex float* shift = md_alloc(DIMS, shift_dims, CFL_SIZE);

        unsigned int X = shift_dims[READ_DIM];
        unsigned int Y = shift_dims[PHS1_DIM];
        unsigned int Z = shift_dims[PHS2_DIM];

        for (unsigned int x = 0; x < X; x++)
            for (unsigned int y = 0; y < Y; y++)
                for (unsigned int z = 0; z < Z; z++)
                    shift[(z * Z + y) * Y + x] = cexp(2.i * M_PI * ((csh[0] * x) / X + (csh[1] * y) / Y + (csh[2] * z) / Z));

        md_zmul2(DIMS, msk_dims, msk_strs, pattern + size, msk_strs, pattern + size, shift_strs, shift);
        md_free(shift);
    }

#if 0
    float scaling = 1. / estimate_scaling(ksp_dims, NULL, kspace_data);
#else
    float scaling = 100. / md_znorm(DIMS, ksp_dims, kspace_data);
#endif
    debug_printf(DP_INFO, "Scaling: %f\n", scaling);
    md_zsmul(DIMS, ksp_dims, kspace_data, kspace_data, scaling);

    if (-1. == restrict_fov) {

        mask = md_alloc(DIMS, msk_dims, CFL_SIZE);
        md_zfill(DIMS, msk_dims, mask, 1.);

    } else {

        float restrict_dims[DIMS] = { [0 ... DIMS - 1] = 1. };
        restrict_dims[0] = restrict_fov;
        restrict_dims[1] = restrict_fov;
        restrict_dims[2] = restrict_fov;
        mask = compute_mask(DIMS, msk_dims, restrict_dims);
    }

#ifdef  USE_CUDA
    if (usegpu) {

        complex float* kspace_gpu = md_alloc_gpu(DIMS, ksp_dims, CFL_SIZE);
        md_copy(DIMS, ksp_dims, kspace_gpu, kspace_data, CFL_SIZE);
        noir_recon(dims, iter, l1, image, NULL, pattern, mask, kspace_gpu, rvc, usegpu);
        md_free(kspace_gpu);

        md_zfill(DIMS, ksp_dims, sens, 1.);

    } else
#endif
        noir_recon(dims, iter, l1, image, sens, pattern, mask, kspace_data, rvc, usegpu);

    if (normalize) {

        md_zrss(DIMS, ksp_dims, COIL_FLAG, norm, sens);
        md_zmul2(DIMS, img_dims, img_strs, image, img_strs, image, msk_strs, norm);
    }

    if (4 == argc) {

        long strs[DIMS];

        md_calc_strides(DIMS, strs, ksp_dims, CFL_SIZE);

        if (norm)
            md_zdiv2(DIMS, ksp_dims, strs, sens, strs, sens, img_strs, norm);

        fftmod(DIMS, ksp_dims, FFT_FLAGS, sens, sens);

        unmap_cfl(DIMS, ksp_dims, sens);

    } else {

        md_free(sens);
    }

    md_free(norm);
    md_free(mask);

    if (NULL != psf)
        unmap_cfl(DIMS, pat_dims, pattern);
    else
        md_free(pattern);


    unmap_cfl(DIMS, img_dims, image);
    unmap_cfl(DIMS, ksp_dims, kspace_data);
    exit(0);
}
Ejemplo n.º 5
0
Archivo: pics.c Proyecto: grlee77/bart
int main_pics(int argc, char* argv[])
{
	// Initialize default parameters

	struct sense_conf conf = sense_defaults;



	bool use_gpu = false;

	bool randshift = true;
	unsigned int maxiter = 30;
	float step = -1.;

	// Start time count

	double start_time = timestamp();

	// Read input options
	struct nufft_conf_s nuconf = nufft_conf_defaults;
	nuconf.toeplitz = false;

	float restrict_fov = -1.;
	const char* pat_file = NULL;
	const char* traj_file = NULL;
	bool scale_im = false;
	bool eigen = false;
	float scaling = 0.;

	unsigned int llr_blk = 8;

	const char* image_truth_file = NULL;
	bool im_truth = false;

	const char* image_start_file = NULL;
	bool warm_start = false;

	bool hogwild = false;
	bool fast = false;
	float admm_rho = iter_admm_defaults.rho;
	unsigned int admm_maxitercg = iter_admm_defaults.maxitercg;

	struct opt_reg_s ropts;
	ropts.r = 0;
	ropts.algo = CG;
	ropts.lambda = -1.;


	const struct opt_s opts[] = {

		{ 'l', true, opt_reg, &ropts, "1/-l2\t\ttoggle l1-wavelet or l2 regularization." },
		OPT_FLOAT('r', &ropts.lambda, "lambda", "regularization parameter"),
		{ 'R', true, opt_reg, &ropts, " <T>:A:B:C\tgeneralized regularization options (-Rh for help)" },
		OPT_SET('c', &conf.rvc, "real-value constraint"),
		OPT_FLOAT('s', &step, "step", "iteration stepsize"),
		OPT_UINT('i', &maxiter, "iter", "max. number of iterations"),
		OPT_STRING('t', &traj_file, "file", "k-space trajectory"),
		OPT_CLEAR('n', &randshift, "disable random wavelet cycle spinning"),
		OPT_SET('g', &use_gpu, "use GPU"),
		OPT_STRING('p', &pat_file, "file", "pattern or weights"),
		OPT_SELECT('I', enum algo_t, &ropts.algo, IST, "(select IST)"),
		OPT_UINT('b', &llr_blk, "blk", "Lowrank block size"),
		OPT_SET('e', &eigen, "Scale stepsize based on max. eigenvalue"),
		OPT_SET('H', &hogwild, "(hogwild)"),
		OPT_SET('F', &fast, "(fast)"),
		OPT_STRING('T', &image_truth_file, "file", "(truth file)"),
		OPT_STRING('W', &image_start_file, "<img>", "Warm start with <img>"),
		OPT_INT('d', &debug_level, "level", "Debug level"),
		OPT_INT('O', &conf.rwiter, "rwiter", "(reweighting)"),
		OPT_FLOAT('o', &conf.gamma, "gamma", "(reweighting)"),
		OPT_FLOAT('u', &admm_rho, "rho", "ADMM rho"),
		OPT_UINT('C', &admm_maxitercg, "iter", "ADMM max. CG iterations"),
		OPT_FLOAT('q', &conf.cclambda, "cclambda", "(cclambda)"),
		OPT_FLOAT('f', &restrict_fov, "rfov", "restrict FOV"),
		OPT_SELECT('m', enum algo_t, &ropts.algo, ADMM, "Select ADMM"),
		OPT_FLOAT('w', &scaling, "val", "scaling"),
		OPT_SET('S', &scale_im, "Re-scale the image after reconstruction"),
	};

	cmdline(&argc, argv, 3, 3, usage_str, help_str, ARRAY_SIZE(opts), opts);

	if (NULL != image_truth_file)
		im_truth = true;

	if (NULL != image_start_file)
		warm_start = true;


	long max_dims[DIMS];
	long map_dims[DIMS];
	long pat_dims[DIMS];
	long img_dims[DIMS];
	long coilim_dims[DIMS];
	long ksp_dims[DIMS];
	long traj_dims[DIMS];



	// load kspace and maps and get dimensions

	complex float* kspace = load_cfl(argv[1], DIMS, ksp_dims);
	complex float* maps = load_cfl(argv[2], DIMS, map_dims);


	complex float* traj = NULL;

	if (NULL != traj_file)
		traj = load_cfl(traj_file, DIMS, traj_dims);


	md_copy_dims(DIMS, max_dims, ksp_dims);
	md_copy_dims(5, max_dims, map_dims);

	md_select_dims(DIMS, ~COIL_FLAG, img_dims, max_dims);
	md_select_dims(DIMS, ~MAPS_FLAG, coilim_dims, max_dims);

	if (!md_check_compat(DIMS, ~(MD_BIT(MAPS_DIM)|FFT_FLAGS), img_dims, map_dims))
		error("Dimensions of image and sensitivities do not match!\n");

	assert(1 == ksp_dims[MAPS_DIM]);


	(use_gpu ? num_init_gpu : num_init)();

	// print options

	if (use_gpu)
		debug_printf(DP_INFO, "GPU reconstruction\n");

	if (map_dims[MAPS_DIM] > 1) 
		debug_printf(DP_INFO, "%ld maps.\nESPIRiT reconstruction.\n", map_dims[MAPS_DIM]);

	if (hogwild)
		debug_printf(DP_INFO, "Hogwild stepsize\n");

	if (im_truth)
		debug_printf(DP_INFO, "Compare to truth\n");



	// initialize sampling pattern

	complex float* pattern = NULL;

	if (NULL != pat_file) {

		pattern = load_cfl(pat_file, DIMS, pat_dims);

		assert(md_check_compat(DIMS, COIL_FLAG, ksp_dims, pat_dims));

	} else {

		md_select_dims(DIMS, ~COIL_FLAG, pat_dims, ksp_dims);
		pattern = md_alloc(DIMS, pat_dims, CFL_SIZE);
		estimate_pattern(DIMS, ksp_dims, COIL_DIM, pattern, kspace);
	}


	if ((NULL != traj_file) && (NULL == pat_file)) {

		md_free(pattern);
		pattern = NULL;
		nuconf.toeplitz = true;

	} else {

		// print some statistics

		long T = md_calc_size(DIMS, pat_dims);
		long samples = (long)pow(md_znorm(DIMS, pat_dims, pattern), 2.);

		debug_printf(DP_INFO, "Size: %ld Samples: %ld Acc: %.2f\n", T, samples, (float)T / (float)samples);
	}

	if (NULL == traj_file) {

		fftmod(DIMS, ksp_dims, FFT_FLAGS, kspace, kspace);
		fftmod(DIMS, map_dims, FFT_FLAGS, maps, maps);
	}

	// apply fov mask to sensitivities

	if (-1. != restrict_fov) {

		float restrict_dims[DIMS] = { [0 ... DIMS - 1] = 1. };
		restrict_dims[0] = restrict_fov;
		restrict_dims[1] = restrict_fov;
		restrict_dims[2] = restrict_fov;

		apply_mask(DIMS, map_dims, maps, restrict_dims);
	}
Ejemplo n.º 6
0
int main_sense(int argc, char* argv[])
{
	struct sense_conf conf = sense_defaults;

	double start_time = timestamp();

	bool admm = false;
	bool ist = false;
	bool use_gpu = false;
	bool l1wav = false;
	bool lowrank = false;
	bool randshift = true;
	int maxiter = 30;
	float step = 0.95;
	float lambda = 0.;

	float restrict_fov = -1.;
	const char* pat_file = NULL;
	const char* traj_file = NULL;
	const char* image_truth_file = NULL;
	bool im_truth = false;
	bool scale_im = false;

	bool hogwild = false;
	bool fast = false;
	float admm_rho = iter_admm_defaults.rho;

	int c;
	while (-1 != (c = getopt(argc, argv, "Fq:l:r:s:i:u:o:O:f:t:cT:Imghp:Sd:H"))) {
		switch(c) {

		case 'H':
			hogwild = true;
			break;

		case 'F':
			fast = true;
			break;

		case 'I':
			ist = true;
			break;

		case 'T':
			im_truth = true;
			image_truth_file = strdup(optarg);
			assert(NULL != image_truth_file);
			break;

		case 'd':
			debug_level = atoi(optarg);
			break;

		case 'r':
			lambda = atof(optarg);
			break;

		case 'O':
			conf.rwiter = atoi(optarg);
			break;

		case 'o':
			conf.gamma = atof(optarg);
			break;

		case 's':
			step = atof(optarg);
			break;

		case 'i':
			maxiter = atoi(optarg);
			break;

		case 'l':
			if (1 == atoi(optarg)) {

				l1wav = true;
				lowrank = false;

			} else
			if (2 == atoi(optarg)) {

				l1wav = false;
				lowrank = false;

			} else
			if (3 == atoi(optarg)) {

				lowrank = true;
				l1wav = false;

			} else {

				usage(argv[0], stderr);
				exit(1);
			}
			break;

		case 'q':
			conf.cclambda = atof(optarg);
			break;

		case 'c':
			conf.rvc = true;
			break;

		case 'f':
			restrict_fov = atof(optarg);
			break;

		case 'm':
			admm = true;
			break;

		case 'u':
			admm_rho = atof(optarg);
			break;

		case 'g':
			use_gpu = true;
			break;

		case 'p':
			pat_file = strdup(optarg);
			break;

		case 't':
			assert(0);
			break;

		case 'S':
			scale_im = true;
			break;

		case 'h':
			usage(argv[0], stdout);
			help();
			exit(0);

		default:
			usage(argv[0], stderr);
			exit(1);
		}
	}

	if (argc - optind != 3) {

		usage(argv[0], stderr);
		exit(1);
	}

	long map_dims[DIMS];
	long pat_dims[DIMS];
	long img_dims[DIMS];
	long ksp_dims[DIMS];
	long max_dims[DIMS];


	// load kspace and maps and get dimensions

	complex float* kspace = load_cfl(argv[optind + 0], DIMS, ksp_dims);
	complex float* maps = load_cfl(argv[optind + 1], DIMS, map_dims);

	md_copy_dims(DIMS, max_dims, ksp_dims);
	max_dims[MAPS_DIM] = map_dims[MAPS_DIM];

	md_select_dims(DIMS, ~COIL_FLAG, pat_dims, ksp_dims);
	md_select_dims(DIMS, ~COIL_FLAG, img_dims, max_dims);

	for (int i = 0; i < 4; i++) {	// sizes2[4] may be > 1
		if (ksp_dims[i] != map_dims[i]) {
		
			fprintf(stderr, "Dimensions of kspace and sensitivities do not match!\n");
			exit(1);
		}
	}


	assert(1 == ksp_dims[MAPS_DIM]);

	(use_gpu ? num_init_gpu : num_init)();

	// print options

	if (use_gpu)
		debug_printf(DP_INFO, "GPU reconstruction\n");

	if (map_dims[MAPS_DIM] > 1) 
		debug_printf(DP_INFO, "%ld maps.\nESPIRiT reconstruction.\n", map_dims[MAPS_DIM]);

	if (l1wav)
		debug_printf(DP_INFO, "l1-wavelet regularization\n");

	if (ist)
		debug_printf(DP_INFO, "Use IST\n");

	if (im_truth)
		debug_printf(DP_INFO, "Compare to truth\n");



	// initialize sampling pattern

	complex float* pattern = NULL;
	long pat_dims2[DIMS];

	if (NULL != pat_file) {

		pattern = load_cfl(pat_file, DIMS, pat_dims2);

		// FIXME: check compatibility
	} else {

		pattern = md_alloc(DIMS, pat_dims, CFL_SIZE);
		estimate_pattern(DIMS, ksp_dims, COIL_DIM, pattern, kspace);
	}


	
	// print some statistics

	size_t T = md_calc_size(DIMS, pat_dims);
	long samples = (long)pow(md_znorm(DIMS, pat_dims, pattern), 2.);
	debug_printf(DP_INFO, "Size: %ld Samples: %ld Acc: %.2f\n", T, samples, (float)T / (float)samples); 

	fftmod(DIMS, ksp_dims, FFT_FLAGS, kspace, kspace);
	fftmod(DIMS, map_dims, FFT_FLAGS, maps, maps);


	// apply fov mask to sensitivities

	if (-1. != restrict_fov) {

		float restrict_dims[DIMS] = { [0 ... DIMS - 1] = 1. };
		restrict_dims[0] = restrict_fov;
		restrict_dims[1] = restrict_fov;
		restrict_dims[2] = restrict_fov;

		apply_mask(DIMS, map_dims, maps, restrict_dims);
	}