/** * Free the linear operator and associated data, * Note: only frees the data if its reference count is zero * * @param op linear operator */ void linop_free(const struct linop_s* op) { operator_free(op->forward); operator_free(op->adjoint); operator_free(op->normal); operator_p_free(op->norm_inv); free((void*)op); }
/** * Perform iterative, multi-regularized least-squares reconstruction */ void lsqr2( unsigned int N, const struct lsqr_conf* conf, italgo_fun2_t italgo, void* iconf, const struct linop_s* model_op, unsigned int num_funs, const struct operator_p_s** prox_funs, const struct linop_s** prox_linops, const long x_dims[N], _Complex float* x, const long y_dims[N], const _Complex float* y, const complex float* x_truth, void* obj_eval_data, float (*obj_eval)(const void*, const float*)) { // ----------------------------------------------------------- // normal equation right hand side complex float* x_adj = md_alloc_sameplace(N, x_dims, CFL_SIZE, y); linop_adjoint(model_op, N, x_dims, x_adj, N, y_dims, y); // ----------------------------------------------------------- // initialize data: struct to hold all data and operators struct lsqr_data data; data.l2_lambda = conf->lambda; data.model_op = model_op; data.G_ops = prox_linops; data.prox_ops = prox_funs; data.size = 2 * md_calc_size(N, x_dims); // ----------------------------------------------------------- // run recon const struct operator_s* normaleq_op = operator_create(N, x_dims, N, x_dims, (void*)&data, normaleq_l2_apply, NULL); italgo(iconf, normaleq_op, num_funs, prox_funs, prox_linops, NULL, data.size, (float*)x, (const float*)x_adj, (const float*)x_truth, obj_eval_data, obj_eval); // ----------------------------------------------------------- // clean up md_free(x_adj); operator_free(normaleq_op); }
/** * Create chain of linear operators. * C = B A * C^H = A^H B^H * C^H C = A^H B^H B A */ struct linop_s* linop_chain(const struct linop_s* a, const struct linop_s* b) { struct linop_s* c = xmalloc(sizeof(struct linop_s)); c->forward = operator_chain(a->forward, b->forward); c->adjoint = operator_chain(b->adjoint, a->adjoint); if (NULL == b->normal) { c->normal = operator_chain(c->forward, c->adjoint); } else { const struct operator_s* top = operator_chain(b->normal, a->adjoint); c->normal = operator_chain(a->forward, top); operator_free(top); } c->norm_inv = NULL; return c; }
void fft_free(const struct operator_s* o) { operator_free(o); }
int main_nufft(int argc, char* argv[]) { bool adjoint = false; bool inverse = false; bool use_gpu = false; bool precond = false; bool dft = false; struct nufft_conf_s conf = nufft_conf_defaults; struct iter_conjgrad_conf cgconf = iter_conjgrad_defaults; long coilim_vec[3] = { 0 }; float lambda = 0.; const struct opt_s opts[] = { OPT_SET('a', &adjoint, "adjoint"), OPT_SET('i', &inverse, "inverse"), OPT_VEC3('d', &coilim_vec, "x:y:z", "dimensions"), OPT_VEC3('D', &coilim_vec, "", "()"), OPT_SET('t', &conf.toeplitz, "Toeplitz embedding for inverse NUFFT"), OPT_SET('c', &precond, "Preconditioning for inverse NUFFT"), OPT_FLOAT('l', &lambda, "lambda", "l2 regularization"), OPT_UINT('m', &cgconf.maxiter, "", "()"), OPT_SET('s', &dft, "DFT"), }; cmdline(&argc, argv, 3, 3, usage_str, help_str, ARRAY_SIZE(opts), opts); long coilim_dims[DIMS] = { 0 }; md_copy_dims(3, coilim_dims, coilim_vec); // Read trajectory long traj_dims[DIMS]; complex float* traj = load_cfl(argv[1], DIMS, traj_dims); assert(3 == traj_dims[0]); num_init(); if (inverse || adjoint) { long ksp_dims[DIMS]; const complex float* ksp = load_cfl(argv[2], DIMS, ksp_dims); assert(1 == ksp_dims[0]); assert(md_check_compat(DIMS, ~(PHS1_FLAG|PHS2_FLAG), ksp_dims, traj_dims)); md_copy_dims(DIMS - 3, coilim_dims + 3, ksp_dims + 3); if (0 == md_calc_size(DIMS, coilim_dims)) { estimate_im_dims(DIMS, coilim_dims, traj_dims, traj); debug_printf(DP_INFO, "Est. image size: %ld %ld %ld\n", coilim_dims[0], coilim_dims[1], coilim_dims[2]); } complex float* img = create_cfl(argv[3], DIMS, coilim_dims); md_clear(DIMS, coilim_dims, img, CFL_SIZE); const struct linop_s* nufft_op; if (!dft) nufft_op = nufft_create(DIMS, ksp_dims, coilim_dims, traj_dims, traj, NULL, conf, use_gpu); else nufft_op = nudft_create(DIMS, FFT_FLAGS, ksp_dims, coilim_dims, traj_dims, traj); if (inverse) { const struct operator_s* precond_op = NULL; if (conf.toeplitz && precond) precond_op = nufft_precond_create(nufft_op); lsqr(DIMS, &(struct lsqr_conf){ lambda }, iter_conjgrad, CAST_UP(&cgconf), nufft_op, NULL, coilim_dims, img, ksp_dims, ksp, precond_op); if (conf.toeplitz && precond) operator_free(precond_op); } else {