const struct operator_s* nufft_precond_create(const struct linop_s* nufft_op) { const auto data = CAST_DOWN(nufft_data, linop_get_data(nufft_op)); PTR_ALLOC(struct nufft_precond_data, pdata); SET_TYPEID(nufft_precond_data, pdata); assert(data->conf.toeplitz); int N = data->N; int ND = N + 1; pdata->N = N; pdata->cim_dims = *TYPE_ALLOC(long[ND]); pdata->pre_dims = *TYPE_ALLOC(long[ND]); pdata->cim_strs = *TYPE_ALLOC(long[ND]); pdata->pre_strs = *TYPE_ALLOC(long[ND]); md_copy_dims(ND, pdata->cim_dims, data->cim_dims); md_select_dims(ND, data->flags, pdata->pre_dims, pdata->cim_dims); md_calc_strides(ND, pdata->cim_strs, pdata->cim_dims, CFL_SIZE); md_calc_strides(ND, pdata->pre_strs, pdata->pre_dims, CFL_SIZE); pdata->pre = compute_precond(pdata->N, pdata->pre_dims, pdata->pre_strs, data->psf_dims, data->psf_strs, data->psf, data->linphase); pdata->fft_op = linop_fft_create(pdata->N, pdata->cim_dims, data->flags); const long* cim_dims = pdata->cim_dims; // need to dereference pdata before PTR_PASS return operator_create(N, cim_dims, N, cim_dims, CAST_UP(PTR_PASS(pdata)), nufft_precond_apply, nufft_precond_del); }
/** * Create sense operator, y = F S x, * where F is the Fourier transform and S is the sensitivity maps * * @param max_dims maximal dimensions across all data structures * @param sens_flags active map dimensions * @param sens sensitivities * @param gpu TRUE if using gpu */ struct linop_s* sense_init(const long max_dims[DIMS], unsigned int sens_flags, const complex float* sens, bool gpu) { long ksp_dims[DIMS]; md_select_dims(DIMS, ~MAPS_FLAG, ksp_dims, max_dims); struct linop_s* fft = linop_fft_create(DIMS, ksp_dims, FFT_FLAGS, gpu); struct linop_s* maps = maps_create(max_dims, sens_flags, sens, gpu); struct linop_s* sense_op = linop_chain(maps, fft); linop_free(fft); linop_free(maps); return sense_op; }
/** * * NUFFT operator initialization * * @param N - number of dimensions * @param ksp_dims - kspace dimension * @param cim_dims - coil images dimension * @param traj - trajectory * @param conf - configuration options * @param use_gpu - use gpu boolean * */ struct linop_s* nufft_create(unsigned int N, const long ksp_dims[N], const long cim_dims[N], const long traj_dims[N], const complex float* traj, const complex float* weights, struct nufft_conf_s conf, bool use_gpu) { struct nufft_data* data = (struct nufft_data*)xmalloc(sizeof(struct nufft_data)); data->N = N; data->use_gpu = use_gpu; data->traj = traj; data->conf = conf; data->width = 3.; data->beta = calc_beta(2., data->width); // get dims assert(md_check_compat(N - 3, 0, ksp_dims + 3, cim_dims + 3)); unsigned int ND = N + 3; data->ksp_dims = xmalloc(ND * sizeof(long)); data->cim_dims = xmalloc(ND * sizeof(long)); data->cml_dims = xmalloc(ND * sizeof(long)); data->img_dims = xmalloc(ND * sizeof(long)); data->trj_dims = xmalloc(ND * sizeof(long)); data->lph_dims = xmalloc(ND * sizeof(long)); data->psf_dims = xmalloc(ND * sizeof(long)); data->wgh_dims = xmalloc(ND * sizeof(long)); data->ksp_strs = xmalloc(ND * sizeof(long)); data->cim_strs = xmalloc(ND * sizeof(long)); data->cml_strs = xmalloc(ND * sizeof(long)); data->img_strs = xmalloc(ND * sizeof(long)); data->trj_strs = xmalloc(ND * sizeof(long)); data->lph_strs = xmalloc(ND * sizeof(long)); data->psf_strs = xmalloc(ND * sizeof(long)); data->wgh_strs = xmalloc(ND * sizeof(long)); md_singleton_dims(ND, data->cim_dims); md_singleton_dims(ND, data->ksp_dims); md_copy_dims(N, data->cim_dims, cim_dims); md_copy_dims(N, data->ksp_dims, ksp_dims); md_select_dims(ND, FFT_FLAGS, data->img_dims, data->cim_dims); assert(3 == traj_dims[0]); assert(traj_dims[1] == ksp_dims[1]); assert(traj_dims[2] == ksp_dims[2]); assert(md_check_compat(N - 3, ~0, traj_dims + 3, ksp_dims + 3)); assert(md_check_bounds(N - 3, ~0, traj_dims + 3, ksp_dims + 3)); md_singleton_dims(ND, data->trj_dims); md_copy_dims(N, data->trj_dims, traj_dims); // get strides md_calc_strides(ND, data->cim_strs, data->cim_dims, CFL_SIZE); md_calc_strides(ND, data->img_strs, data->img_dims, CFL_SIZE); md_calc_strides(ND, data->trj_strs, data->trj_dims, CFL_SIZE); md_calc_strides(ND, data->ksp_strs, data->ksp_dims, CFL_SIZE); data->weights = NULL; if (NULL != weights) { md_singleton_dims(ND, data->wgh_dims); md_select_dims(N, ~MD_BIT(0), data->wgh_dims, data->trj_dims); md_calc_strides(ND, data->wgh_strs, data->wgh_dims, CFL_SIZE); complex float* tmp = md_alloc(ND, data->wgh_dims, CFL_SIZE); md_copy(ND, data->wgh_dims, tmp, weights, CFL_SIZE); data->weights = tmp; } complex float* roll = md_alloc(ND, data->img_dims, CFL_SIZE); rolloff_correction(2., data->width, data->beta, data->img_dims, roll); data->roll = roll; complex float* linphase = compute_linphases(N, data->lph_dims, data->img_dims); md_calc_strides(ND, data->lph_strs, data->lph_dims, CFL_SIZE); if (!conf.toeplitz) md_zmul2(ND, data->lph_dims, data->lph_strs, linphase, data->lph_strs, linphase, data->img_strs, data->roll); fftmod(ND, data->lph_dims, FFT_FLAGS, linphase, linphase); fftscale(ND, data->lph_dims, FFT_FLAGS, linphase, linphase); // md_zsmul(ND, data->lph_dims, linphase, linphase, 1. / (float)(data->trj_dims[1] * data->trj_dims[2])); complex float* fftm = md_alloc(ND, data->img_dims, CFL_SIZE); md_zfill(ND, data->img_dims, fftm, 1.); fftmod(ND, data->img_dims, FFT_FLAGS, fftm, fftm); data->fftmod = fftm; data->linphase = linphase; data->psf = NULL; if (conf.toeplitz) { #if 0 md_copy_dims(ND, data->psf_dims, data->lph_dims); #else md_copy_dims(3, data->psf_dims, data->lph_dims); md_copy_dims(ND - 3, data->psf_dims + 3, data->trj_dims + 3); data->psf_dims[N] = data->lph_dims[N]; #endif md_calc_strides(ND, data->psf_strs, data->psf_dims, CFL_SIZE); data->psf = compute_psf2(N, data->psf_dims, data->trj_dims, data->traj, data->weights); } md_copy_dims(ND, data->cml_dims, data->cim_dims); data->cml_dims[N + 0] = data->lph_dims[N + 0]; md_calc_strides(ND, data->cml_strs, data->cml_dims, CFL_SIZE); data->cm2_dims = xmalloc(ND * sizeof(long)); // ! md_copy_dims(ND, data->cm2_dims, data->cim_dims); for (int i = 0; i < 3; i++) data->cm2_dims[i] = (1 == cim_dims[i]) ? 1 : (2 * cim_dims[i]); data->grid = md_alloc(ND, data->cml_dims, CFL_SIZE); data->fft_op = linop_fft_create(ND, data->cml_dims, FFT_FLAGS, use_gpu); return linop_create(N, ksp_dims, N, cim_dims, data, nufft_apply, nufft_apply_adjoint, nufft_apply_normal, NULL, nufft_free_data); }
void opt_reg_configure(unsigned int N, const long img_dims[N], struct opt_reg_s* ropts, const struct operator_p_s* prox_ops[NUM_REGS], const struct linop_s* trafos[NUM_REGS], unsigned int llr_blk, bool randshift, bool use_gpu) { float lambda = ropts->lambda; if (-1. == lambda) lambda = 0.; // if no penalities specified but regularization // parameter is given, add a l2 penalty struct reg_s* regs = ropts->regs; if ((0 == ropts->r) && (lambda > 0.)) { regs[0].xform = L2IMG; regs[0].xflags = 0u; regs[0].jflags = 0u; regs[0].lambda = lambda; ropts->r = 1; } int nr_penalties = ropts->r; long blkdims[MAX_LEV][DIMS]; int levels; for (int nr = 0; nr < nr_penalties; nr++) { // fix up regularization parameter if (-1. == regs[nr].lambda) regs[nr].lambda = lambda; switch (regs[nr].xform) { case L1WAV: debug_printf(DP_INFO, "l1-wavelet regularization: %f\n", regs[nr].lambda); if (0 != regs[nr].jflags) debug_printf(DP_WARN, "joint l1-wavelet thresholding not currently supported.\n"); 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); unsigned int wflags = 0; for (unsigned int i = 0; i < DIMS; i++) { if ((1 < img_dims[i]) && MD_IS_SET(regs[nr].xflags, i)) { wflags = MD_SET(wflags, i); minsize[i] = MIN(img_dims[i], 16); } } trafos[nr] = linop_identity_create(DIMS, img_dims); prox_ops[nr] = prox_wavelet3_thresh_create(DIMS, img_dims, wflags, minsize, regs[nr].lambda, randshift); break; case TV: debug_printf(DP_INFO, "TV regularization: %f\n", regs[nr].lambda); trafos[nr] = linop_grad_create(DIMS, img_dims, regs[nr].xflags); prox_ops[nr] = prox_thresh_create(DIMS + 1, linop_codomain(trafos[nr])->dims, regs[nr].lambda, regs[nr].jflags | MD_BIT(DIMS), use_gpu); break; case LLR: debug_printf(DP_INFO, "lowrank regularization: %f\n", regs[nr].lambda); // add locally lowrank penalty levels = llr_blkdims(blkdims, regs[nr].jflags, img_dims, llr_blk); assert(1 == levels); assert(levels == img_dims[LEVEL_DIM]); for(int l = 0; l < levels; l++) #if 0 blkdims[l][MAPS_DIM] = img_dims[MAPS_DIM]; #else blkdims[l][MAPS_DIM] = 1; #endif int remove_mean = 0; trafos[nr] = linop_identity_create(DIMS, img_dims); prox_ops[nr] = lrthresh_create(img_dims, randshift, regs[nr].xflags, (const long (*)[DIMS])blkdims, regs[nr].lambda, false, remove_mean, use_gpu); break; case MLR: #if 0 // FIXME: multiscale low rank changes the output image dimensions // and requires the forward linear operator. This should be decoupled... debug_printf(DP_INFO, "multi-scale lowrank regularization: %f\n", regs[nr].lambda); levels = multilr_blkdims(blkdims, regs[nr].jflags, img_dims, 8, 1); img_dims[LEVEL_DIM] = levels; max_dims[LEVEL_DIM] = levels; for(int l = 0; l < levels; l++) blkdims[l][MAPS_DIM] = 1; trafos[nr] = linop_identity_create(DIMS, img_dims); prox_ops[nr] = lrthresh_create(img_dims, randshift, regs[nr].xflags, (const long (*)[DIMS])blkdims, regs[nr].lambda, false, 0, use_gpu); const struct linop_s* decom_op = sum_create( img_dims, use_gpu ); const struct linop_s* tmp_op = forward_op; forward_op = linop_chain(decom_op, forward_op); linop_free(decom_op); linop_free(tmp_op); #else debug_printf(DP_WARN, "multi-scale lowrank regularization not yet supported: %f\n", regs[nr].lambda); #endif break; case IMAGL1: debug_printf(DP_INFO, "l1 regularization of imaginary part: %f\n", regs[nr].lambda); trafos[nr] = linop_rdiag_create(DIMS, img_dims, 0, &(complex float){ 1.i }); prox_ops[nr] = prox_thresh_create(DIMS, img_dims, regs[nr].lambda, regs[nr].jflags, use_gpu); break; case IMAGL2: debug_printf(DP_INFO, "l2 regularization of imaginary part: %f\n", regs[nr].lambda); trafos[nr] = linop_rdiag_create(DIMS, img_dims, 0, &(complex float){ 1.i }); prox_ops[nr] = prox_leastsquares_create(DIMS, img_dims, regs[nr].lambda, NULL); break; case L1IMG: debug_printf(DP_INFO, "l1 regularization: %f\n", regs[nr].lambda); trafos[nr] = linop_identity_create(DIMS, img_dims); prox_ops[nr] = prox_thresh_create(DIMS, img_dims, regs[nr].lambda, regs[nr].jflags, use_gpu); break; case L2IMG: debug_printf(DP_INFO, "l2 regularization: %f\n", regs[nr].lambda); trafos[nr] = linop_identity_create(DIMS, img_dims); prox_ops[nr] = prox_leastsquares_create(DIMS, img_dims, regs[nr].lambda, NULL); break; case FTL1: debug_printf(DP_INFO, "l1 regularization of Fourier transform: %f\n", regs[nr].lambda); trafos[nr] = linop_fft_create(DIMS, img_dims, regs[nr].xflags); prox_ops[nr] = prox_thresh_create(DIMS, img_dims, regs[nr].lambda, regs[nr].jflags, use_gpu); break; }