static void unisoftthresh_apply(const operator_data_t* _data, float mu, complex float* dst, const complex float* src) { const auto data = CAST_DOWN(thresh_s, _data); if (0. == mu) { md_copy(data->D, data->dim, dst, src, CFL_SIZE); } else { const long* transform_dims = linop_codomain(data->unitary_op)->dims; const long* transform_strs = linop_codomain(data->unitary_op)->strs; complex float* tmp = md_alloc_sameplace(data->D, transform_dims, CFL_SIZE, dst); linop_forward(data->unitary_op, data->D, transform_dims, tmp, data->D, data->dim, src); complex float* tmp_norm = md_alloc_sameplace(data->D, data->norm_dim, CFL_SIZE, dst); md_zsoftthresh_core2(data->D, transform_dims, data->lambda * mu, data->flags, tmp_norm, transform_strs, tmp, transform_strs, tmp); md_free(tmp_norm); linop_adjoint(data->unitary_op, data->D, data->dim, dst, data->D, transform_dims, tmp); md_free(tmp); } }
/** * Undersampled FFT adjoint operator */ void ufft_apply_adjoint(const linop_data_t* _data, complex float* dst, const complex float* src) { const struct ufft_data* data = CONTAINER_OF(_data, const struct ufft_data, base); md_zmul2(DIMS, data->ksp_dims, data->ksp_strs, dst, data->ksp_strs, src, data->pat_strs, data->pat); linop_adjoint(data->fft_op, DIMS, data->ksp_dims, dst, DIMS, data->ksp_dims, dst); }
/** * Undersampled FFT adjoint operator */ void ufft_apply_adjoint(const linop_data_t* _data, complex float* dst, const complex float* src) { struct ufft_data* data = CAST_DOWN(ufft_data, _data); md_zmul2(DIMS, data->ksp_dims, data->ksp_strs, dst, data->ksp_strs, src, data->pat_strs, data->pat); linop_adjoint(data->fft_op, DIMS, data->ksp_dims, dst, DIMS, data->ksp_dims, dst); }
/** * Apply the pseudo-inverse operation of a linear operator: x = (A^H A + lambda I)^-1 A^H y * Checks that dimensions are consistent for the linear operator * * @param op linear operator * @param lambda regularization parameter * @param DN number of destination dimensions * @param ddims dimensions of the output (domain) * @param dst output data * @param SN number of source dimensions * @param sdims dimensions of the input (codomain) * @param src input data */ void linop_pseudo_inv(const struct linop_s* op, float lambda, unsigned int DN, const long ddims[DN], complex float* dst, unsigned int SN, const long sdims[SN], const complex float* src) { complex float* adj = md_alloc_sameplace(DN, ddims, CFL_SIZE, dst); linop_adjoint(op, DN, ddims, adj, SN, sdims, src); assert(op->norm_inv); operator_p_apply(op->norm_inv, lambda, DN, ddims, dst, DN, ddims, adj); md_free(adj); }
static void toeplitz_mult(const struct nufft_data* data, complex float* dst, const complex float* src) { unsigned int ND = data->N + 3; md_zmul2(ND, data->cml_dims, data->cml_strs, data->grid, data->cim_strs, src, data->lph_strs, data->linphase); linop_forward(data->fft_op, ND, data->cml_dims, data->grid, ND, data->cml_dims, data->grid); md_zmul2(ND, data->cml_dims, data->cml_strs, data->grid, data->cml_strs, data->grid, data->psf_strs, data->psf); linop_adjoint(data->fft_op, ND, data->cml_dims, data->grid, ND, data->cml_dims, data->grid); md_clear(ND, data->cim_dims, dst, CFL_SIZE); md_zfmacc2(ND, data->cml_dims, data->cim_strs, dst, data->cml_strs, data->grid, data->lph_strs, data->linphase); }
/** * 1/2 || Ax - b ||^2 + rho/2 || x - y ||^2 * * x = (ATA + lI)^-1 b * * X = 1 / (pat^2 + l) B * */ static void ufft_apply_pinverse(const linop_data_t* _data, float rho, complex float* dst, const complex float* src) { const struct ufft_data* data = CONTAINER_OF(_data, const struct ufft_data, base); md_zsadd(DIMS, data->pat_dims, data->pat, data->pat, rho); linop_forward(data->fft_op, DIMS, data->ksp_dims, dst, DIMS, data->ksp_dims, src); md_zdiv2(DIMS, data->ksp_dims, data->ksp_strs, dst, data->ksp_strs, dst, data->pat_strs, data->pat); linop_adjoint(data->fft_op, DIMS, data->ksp_dims, dst, DIMS, data->ksp_dims, dst); md_zsadd(DIMS, data->pat_dims, data->pat, data->pat, -rho); }
static void nufft_precond_apply(const operator_data_t* _data, unsigned int M, void* args[M]) { assert(2 == M); const auto data = CAST_DOWN(nufft_precond_data, _data); complex float* dst = args[0]; const complex float* src = args[1]; linop_forward(data->fft_op, data->N, data->cim_dims, dst, data->N, data->cim_dims, src); md_zdiv2(data->N, data->cim_dims, data->cim_strs, dst, data->cim_strs, dst, data->pre_strs, data->pre); linop_adjoint(data->fft_op, data->N, data->cim_dims, dst, data->N, data->cim_dims, dst); }
/** * 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); }
const struct operator_p_s* prox_lineq_create(const struct linop_s* op, const complex float* y) { PTR_ALLOC(struct prox_lineq_data, pdata); unsigned int N = linop_domain(op)->N; const long* dims = linop_domain(op)->dims; pdata->op = op; pdata->adj = md_alloc_sameplace(N, dims, CFL_SIZE, y); linop_adjoint(op, N, dims, pdata->adj, N, linop_codomain(op)->dims, y); pdata->tmp = md_alloc_sameplace(N, dims, CFL_SIZE, y); return operator_p_create(N, dims, N, dims, CAST_UP(PTR_PASS(pdata)), prox_lineq_apply, prox_lineq_del); }
// Adjoint: from kspace to image static void nufft_apply_adjoint(const void* _data, complex float* dst, const complex float* src) { const struct nufft_data* data = _data; unsigned int ND = data->N + 3; complex float* gridX = md_alloc(data->N, data->cm2_dims, CFL_SIZE); md_clear(data->N, data->cm2_dims, gridX, CFL_SIZE); complex float* wdat = NULL; if (NULL != data->weights) { wdat = md_alloc(data->N, data->ksp_dims, CFL_SIZE); md_zmulc2(data->N, data->ksp_dims, data->ksp_strs, wdat, data->ksp_strs, src, data->wgh_strs, data->weights); src = wdat; } grid2(2., data->width, data->beta, ND, data->trj_dims, data->traj, data->cm2_dims, gridX, data->ksp_dims, src); md_free(wdat); long factors[data->N]; for (unsigned int i = 0; i < data->N; i++) factors[i] = ((data->img_dims[i] > 1) && (i < 3)) ? 2 : 1; md_decompose(data->N, factors, data->cml_dims, data->grid, data->cm2_dims, gridX, CFL_SIZE); md_free(gridX); md_zmulc2(ND, data->cml_dims, data->cml_strs, data->grid, data->cml_strs, data->grid, data->img_strs, data->fftmod); linop_adjoint(data->fft_op, ND, data->cml_dims, data->grid, ND, data->cml_dims, data->grid); md_clear(ND, data->cim_dims, dst, CFL_SIZE); md_zfmacc2(ND, data->cml_dims, data->cim_strs, dst, data->cml_strs, data->grid, data->lph_strs, data->linphase); if (data->conf.toeplitz) md_zmul2(ND, data->cim_dims, data->cim_strs, dst, data->cim_strs, dst, data->img_strs, data->roll); }