/** * Proximal function for f(z) = 0.5 || y - A z ||_2^2. * Solution is (A^H A + (1/mu) I)z = A^H y + (1/mu)(x_plus_u) * * @param prox_data should be of type prox_normaleq_data * @param mu proximal penalty * @param z output * @param x_plus_u input */ static void prox_normaleq_fun(const operator_data_t* prox_data, float mu, float* z, const float* x_plus_u) { struct prox_normaleq_data* pdata = CAST_DOWN(prox_normaleq_data, prox_data); if (0 == mu) { md_copy(1, MD_DIMS(pdata->size), z, x_plus_u, FL_SIZE); } else { float rho = 1. / mu; float* b = md_alloc_sameplace(1, MD_DIMS(pdata->size), FL_SIZE, x_plus_u); md_copy(1, MD_DIMS(pdata->size), b, pdata->adj, FL_SIZE); md_axpy(1, MD_DIMS(pdata->size), b, rho, x_plus_u); if (NULL == pdata->op->norm_inv) { struct iter_conjgrad_conf* cg_conf = pdata->cgconf; cg_conf->l2lambda = rho; iter_conjgrad(CAST_UP(cg_conf), pdata->op->normal, NULL, pdata->size, z, (float*)b, NULL); } else { linop_norm_inv_iter((struct linop_s*)pdata->op, rho, z, b); } md_free(b); } }
void noir_recon(const struct noir_conf_s* conf, const long dims[DIMS], complex float* outbuf, complex float* sensout, const complex float* psf, const complex float* mask, const complex float* kspace) { long imgs_dims[DIMS]; long coil_dims[DIMS]; long data_dims[DIMS]; long img1_dims[DIMS]; md_select_dims(DIMS, FFT_FLAGS|MAPS_FLAG|CSHIFT_FLAG, imgs_dims, dims); md_select_dims(DIMS, FFT_FLAGS|COIL_FLAG|MAPS_FLAG, coil_dims, dims); md_select_dims(DIMS, FFT_FLAGS|COIL_FLAG, data_dims, dims); md_select_dims(DIMS, FFT_FLAGS, img1_dims, dims); long skip = md_calc_size(DIMS, imgs_dims); long size = skip + md_calc_size(DIMS, coil_dims); long data_size = md_calc_size(DIMS, data_dims); long d1[1] = { size }; complex float* img = md_alloc_sameplace(1, d1, CFL_SIZE, kspace); complex float* imgH = md_alloc_sameplace(1, d1, CFL_SIZE, kspace); md_clear(DIMS, imgs_dims, img, CFL_SIZE); md_zfill(DIMS, img1_dims, outbuf, 1.); // initial only first image md_copy(DIMS, img1_dims, img, outbuf, CFL_SIZE); md_clear(DIMS, coil_dims, img + skip, CFL_SIZE); md_clear(DIMS, imgs_dims, imgH, CFL_SIZE); md_clear(DIMS, coil_dims, imgH + skip, CFL_SIZE); struct noir_data* ndata = noir_init(dims, mask, psf, conf->rvc, conf->usegpu); struct data data = { ndata }; struct iter3_irgnm_conf irgnm_conf = { .iter = conf->iter, .alpha = conf->alpha, .redu = conf->redu }; iter3_irgnm(&irgnm_conf.base, frw, der, adj, &data, size * 2, (float*)img, data_size * 2, (const float*)kspace); md_copy(DIMS, imgs_dims, outbuf, img, CFL_SIZE); if (NULL != sensout) { assert(!conf->usegpu); noir_forw_coils(ndata, sensout, img + skip); } noir_free(ndata); md_free(img); md_free(imgH); }
int main_fft(int argc, char* argv[]) { bool unitary = false; bool inv = false; const struct opt_s opts[] = { OPT_SET('u', &unitary, "unitary"), OPT_SET('i', &inv, "inverse"), }; cmdline(&argc, argv, 3, 3, usage_str, help_str, ARRAY_SIZE(opts), opts); long dims[DIMS]; complex float* idata = load_cfl(argv[2], DIMS, dims); complex float* data = create_cfl(argv[3], DIMS, dims); unsigned long flags = labs(atol(argv[1])); md_copy(DIMS, dims, data, idata, sizeof(complex float)); unmap_cfl(DIMS, dims, idata); if (unitary) fftscale(DIMS, dims, flags, data, data); (inv ? ifftc : fftc)(DIMS, dims, flags, data, data); unmap_cfl(DIMS, dims, data); exit(0); }
/** * Proximal function for f(z) = 0 * Solution is z = x_plus_u * * @param prox_data should be of type prox_zero_data * @param mu proximal penalty * @param z output * @param x_plus_u input */ static void prox_zero_fun(const operator_data_t* prox_data, float mu, float* z, const float* x_plus_u) { UNUSED(mu); struct prox_zero_data* pdata = CAST_DOWN(prox_zero_data, prox_data); md_copy(1, MD_DIMS(pdata->size), z, x_plus_u, FL_SIZE); }
static struct ufft_data* ufft_create_data(const long ksp_dims[DIMS], const long pat_dims[DIMS], const complex float* pat, unsigned int flags, bool use_gpu) { PTR_ALLOC(struct ufft_data, data); SET_TYPEID(ufft_data, data); data->flags = flags; data->use_gpu = use_gpu; md_copy_dims(DIMS, data->pat_dims, pat_dims); md_copy_dims(DIMS, data->ksp_dims, ksp_dims); md_calc_strides(DIMS, data->pat_strs, pat_dims, CFL_SIZE); md_calc_strides(DIMS, data->ksp_strs, ksp_dims, CFL_SIZE); #ifdef USE_CUDA data->pat = (use_gpu ? md_alloc_gpu : md_alloc)(DIMS, data->pat_dims, CFL_SIZE); #else data->pat = md_alloc(DIMS, data->pat_dims, CFL_SIZE); #endif md_copy(DIMS, data->pat_dims, data->pat, pat, CFL_SIZE); data->fft_op = linop_fftc_create(DIMS, ksp_dims, flags); return PTR_PASS(data); }
static struct maps_data* maps_create_data(const long max_dims[DIMS], unsigned int sens_flags, const complex float* sens, bool gpu) { struct maps_data* data = xmalloc(sizeof(struct maps_data)); // maximal dimensions md_copy_dims(DIMS, data->max_dims, max_dims); // sensitivity dimensions md_select_dims(DIMS, sens_flags, data->mps_dims, max_dims); md_calc_strides(DIMS, data->strs_mps, data->mps_dims, CFL_SIZE); md_select_dims(DIMS, ~MAPS_FLAG, data->ksp_dims, max_dims); md_calc_strides(DIMS, data->strs_ksp, data->ksp_dims, CFL_SIZE); md_select_dims(DIMS, ~COIL_FLAG, data->img_dims, max_dims); md_calc_strides(DIMS, data->strs_img, data->img_dims, CFL_SIZE); #ifdef USE_CUDA complex float* nsens = (gpu ? md_alloc_gpu : md_alloc)(DIMS, data->mps_dims, CFL_SIZE); #else assert(!gpu); complex float* nsens = md_alloc(DIMS, data->mps_dims, CFL_SIZE); #endif md_copy(DIMS, data->mps_dims, nsens, sens, CFL_SIZE); data->sens = nsens; data->norm = NULL; return data; }
static void linop_cdf97_adjoint(const linop_data_t* _data, complex float* out, const complex float* in) { const struct linop_cdf97_s* data = CAST_DOWN(linop_cdf97_s, _data); md_copy(data->N, data->dims, out, in, CFL_SIZE); md_icdf97z(data->N, data->dims, data->flags, out); }
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); } }
void dump_cfl(const char* name, int D, const long dimensions[D], const complex float* src) { complex float* out = create_cfl(name, D, dimensions); md_copy(D, dimensions, out, src, sizeof(complex float)); unmap_cfl(D, dimensions, out); }
static void fft_linop_normal(const linop_data_t* _data, complex float* out, const complex float* in) { const struct fft_linop_s* data = CAST_DOWN(fft_linop_s, _data); if (data->center) md_copy(data->N, data->dims, out, in, CFL_SIZE); else md_zsmul(data->N, data->dims, out, in, data->nscale); }
/* * Nuclear norm calculation for arbitrary block sizes */ float lrnucnorm(const struct operator_p_s* op, const complex float* src) { struct lrthresh_data_s* data = (struct lrthresh_data_s*)operator_p_get_data(op); long strs1[DIMS]; md_calc_strides(DIMS, strs1, data->dims_decom, 1); float nnorm = 0.; for (int l = 0; l < data->levels; l++) { const complex float* srcl = src + l * strs1[LEVEL_DIM]; // Initialize long blkdims[DIMS]; long blksize = 1; for (unsigned int i = 0; i < DIMS; i++) { blkdims[i] = data->blkdims[l][i]; blksize *= blkdims[i]; } // Special case if blocksize is 1 if (blksize == 1) { for (long j = 0; j < md_calc_size(DIMS, data->dims); j++) nnorm += 2 * cabsf(srcl[j]); continue; } // Initialize data struct svthresh_blockproc_data* svdata = svthresh_blockproc_create(data->mflags, 0., 0); // Initialize tmp complex float* tmp; #ifdef USE_CUDA tmp = (data->use_gpu ? md_alloc_gpu : md_alloc)(DIMS, data->dims, CFL_SIZE); #else tmp = md_alloc(DIMS, data->dims, CFL_SIZE); #endif // Copy to tmp //debug_print_dims(DP_DEBUG1, DIMS, data->dims); md_copy(DIMS, data->dims, tmp, srcl, CFL_SIZE); // Block SVD Threshold nnorm = blockproc(DIMS, data->dims, blkdims, (void*)svdata, nucnorm_blockproc, tmp, tmp); // Free tmp free(svdata); md_free(tmp); } return nnorm; }
int main_cdf97(int argc, char* argv[]) { int c; _Bool inv = false; while (-1 != (c = getopt(argc, argv, "ih"))) { switch (c) { case 'i': inv = 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); } unsigned int flags = atoi(argv[optind + 0]); long dims[DIMS]; complex float* idata = load_cfl(argv[optind + 1], DIMS, dims); complex float* odata = create_cfl(argv[optind + 2], DIMS, dims); md_copy(DIMS, dims, odata, idata, CFL_SIZE); unmap_cfl(DIMS, dims, idata); if (inv) { md_iresortz(DIMS, dims, flags, odata); md_icdf97z(DIMS, dims, flags, odata); } else { md_cdf97z(DIMS, dims, flags, odata); md_resortz(DIMS, dims, flags, odata); } unmap_cfl(DIMS, dims, odata); exit(0); }
static bool test_md_swap(void) { enum { N = 4 }; long dims[N] = { 10, 10, 10, 10 }; complex float* a = md_alloc(N, dims, sizeof(complex float)); complex float* b = md_alloc(N, dims, sizeof(complex float)); complex float* c = md_alloc(N, dims, sizeof(complex float)); md_gaussian_rand(N, dims, a); md_gaussian_rand(N, dims, b); md_gaussian_rand(N, dims, c); complex float* d = md_alloc(N, dims, sizeof(complex float)); complex float* e = md_alloc(N, dims, sizeof(complex float)); complex float* f = md_alloc(N, dims, sizeof(complex float)); md_copy(N, dims, d, a, sizeof(complex float)); md_copy(N, dims, e, b, sizeof(complex float)); md_copy(N, dims, f, c, sizeof(complex float)); md_circular_swap(3, N, dims, (void*[]){ a, b, c }, sizeof(complex float));
/** * Proximal function for f(z) = lambda / 2 || y - z ||_2^2. * Solution is z = (mu * lambda * y + x_plus_u) / (mu * lambda + 1) * * @param prox_data should be of type prox_leastsquares_data * @param mu proximal penalty * @param z output * @param x_plus_u input */ static void prox_leastsquares_fun(const operator_data_t* prox_data, float mu, float* z, const float* x_plus_u) { struct prox_leastsquares_data* pdata = CAST_DOWN(prox_leastsquares_data, prox_data); md_copy(1, MD_DIMS(pdata->size), z, x_plus_u, FL_SIZE); if (0 != mu) { if (NULL != pdata->y) md_axpy(1, MD_DIMS(pdata->size), z, pdata->lambda * mu, pdata->y); md_smul(1, MD_DIMS(pdata->size), z, z, 1. / (mu * pdata->lambda + 1)); } }
static void softthresh_apply(const operator_data_t* _data, float mu, complex float* optr, const complex float* iptr) { const auto data = CAST_DOWN(thresh_s, _data); if (0. == mu) { md_copy(data->D, data->dim, optr, iptr, CFL_SIZE); } else { complex float* tmp_norm = md_alloc_sameplace(data->D, data->norm_dim, CFL_SIZE, optr); md_zsoftthresh_core2(data->D, data->dim, data->lambda * mu, data->flags, tmp_norm, data->str, optr, data->str, iptr); md_free(tmp_norm); } }
void md_gaussian_rand(unsigned int D, const long dims[D], complex float* dst) { #ifdef USE_CUDA if (cuda_ondevice(dst)) { complex float* tmp = md_alloc(D, dims, sizeof(complex float)); md_gaussian_rand(D, dims, tmp); md_copy(D, dims, dst, tmp, sizeof(complex float)); md_free(tmp); return; } #endif //#pragma omp parallel for for (long i = 0; i < md_calc_size(D, dims); i++) dst[i] = (float)gaussian_rand(); }
int main_reshape(int argc, char* argv[]) { cmdline(&argc, argv, 3, 100, usage_str, help_str, 0, NULL); num_init(); unsigned int flags = atoi(argv[1]); unsigned int n = bitcount(flags); assert((int)n + 3 == argc - 1); long in_dims[DIMS]; long in_strs[DIMS]; long out_dims[DIMS]; long out_strs[DIMS]; complex float* in_data = load_cfl(argv[n + 2], DIMS, in_dims); md_calc_strides(DIMS, in_strs, in_dims, CFL_SIZE); md_copy_dims(DIMS, out_dims, in_dims); unsigned int j = 0; for (unsigned int i = 0; i < DIMS; i++) if (MD_IS_SET(flags, i)) out_dims[i] = atoi(argv[j++ + 2]); assert(j == n); assert(md_calc_size(DIMS, in_dims) == md_calc_size(DIMS, out_dims)); md_calc_strides(DIMS, out_strs, out_dims, CFL_SIZE); for (unsigned int i = 0; i < DIMS; i++) if (!(MD_IS_SET(flags, i) || (in_strs[i] == out_strs[i]))) error("Dimensions are not consistent at index %d.\n"); complex float* out_data = create_cfl(argv[n + 3], DIMS, out_dims); md_copy(DIMS, in_dims, out_data, in_data, CFL_SIZE); unmap_cfl(DIMS, in_dims, in_data); unmap_cfl(DIMS, out_dims, out_data); exit(0); }
void circshift(struct wavelet_plan_s* plan, data_t* data) { bool shift = false; int N = plan->numdims_tr; for (int i = 0; i < N; i++) shift |= (0 != plan->randShift_tr[i]); if (shift) { void* data_copy = md_alloc_sameplace(N, plan->imSize_tr, sizeof(data_t), data); md_copy(N, plan->imSize_tr, data_copy, data, sizeof(data_t)); md_circ_shift(N, plan->imSize_tr, plan->randShift_tr, data, data_copy, sizeof(data_t)); md_free(data_copy); } }
/* * Nuclear norm calculation for arbitrary block sizes */ float lrnucnorm(const struct operator_p_s* op, const complex float* src) { struct lrthresh_data_s* data = (struct lrthresh_data_s*)operator_p_get_data(op); long strs1[DIMS]; md_calc_strides(DIMS, strs1, data->dims_decom, 1); float nnorm = 0.; for (int l = 0; l < data->levels; l++) { const complex float* srcl = src + l * strs1[LEVEL_DIM]; long blkdims[DIMS]; long blksize = 1; for (unsigned int i = 0; i < DIMS; i++) { blkdims[i] = data->blkdims[l][i]; blksize *= blkdims[i]; } if (1 == blksize) { for (long j = 0; j < md_calc_size(DIMS, data->dims); j++) nnorm += 2 * cabsf(srcl[j]); continue; } struct svthresh_blockproc_data* svdata = svthresh_blockproc_create(data->mflags, 0., 0); complex float* tmp = md_alloc_sameplace(DIMS, data->dims, CFL_SIZE, src); //debug_print_dims(DP_DEBUG1, DIMS, data->dims); md_copy(DIMS, data->dims, tmp, srcl, CFL_SIZE); // Block SVD Threshold nnorm = blockproc(DIMS, data->dims, blkdims, (void*)svdata, nucnorm_blockproc, tmp, tmp); xfree(svdata); md_free(tmp); } return nnorm; }
void noir_fun(struct noir_data* data, complex float* dst, const complex float* src) { long split = md_calc_size(DIMS, data->imgs_dims); md_copy(DIMS, data->imgs_dims, data->xn, src, CFL_SIZE); noir_forw_coils(data, data->sens, src + split); md_clear(DIMS, data->sign_dims, data->tmp, CFL_SIZE); md_zfmac2(DIMS, data->sign_dims, data->sign_strs, data->tmp, data->imgs_strs, src, data->coil_strs, data->sens); // could be moved to the benning, but see comment below md_zmul2(DIMS, data->sign_dims, data->sign_strs, data->tmp, data->sign_strs, data->tmp, data->mask_strs, data->mask); fft(DIMS, data->sign_dims, FFT_FLAGS, data->tmp, data->tmp); md_clear(DIMS, data->data_dims, dst, CFL_SIZE); md_zfmac2(DIMS, data->sign_dims, data->data_strs, dst, data->sign_strs, data->tmp, data->ptrn_strs, data->pattern); }
/** * Proximal function for f(z) = Ind{ || y - z ||_2 < eps } * * @param prox_data should be of type prox_l2ball_data * @param mu proximal penalty * @param z output * @param x_plus_u input */ static void prox_l2ball_fun(const operator_data_t* prox_data, float mu, float* z, const float* x_plus_u) { UNUSED(mu); struct prox_l2ball_data* pdata = CAST_DOWN(prox_l2ball_data, prox_data); if (NULL != pdata->center) md_sub(1, MD_DIMS(pdata->size), z, x_plus_u, pdata->center); else md_copy(1, MD_DIMS(pdata->size), z, x_plus_u, FL_SIZE); float q1 = md_norm(1, MD_DIMS(pdata->size), z); if (q1 > pdata->eps) md_smul(1, MD_DIMS(pdata->size), z, z, pdata->eps / q1); if (NULL != pdata->center) md_add(1, MD_DIMS(pdata->size), z, z, pdata->center); }
void data_consistency(const long dims[DIMS], complex float* dst, const complex float* pattern, const complex float* kspace1, const complex float* kspace2) { assert(1 == dims[MAPS_DIM]); long strs[DIMS]; long dims1[DIMS]; long strs1[DIMS]; md_select_dims(DIMS, ~COIL_FLAG, dims1, dims); md_calc_strides(DIMS, strs1, dims1, CFL_SIZE); md_calc_strides(DIMS, strs, dims, CFL_SIZE); complex float* tmp = md_alloc_sameplace(DIMS, dims, CFL_SIZE, dst); md_zmul2(DIMS, dims, strs, tmp, strs, kspace2, strs1, pattern); md_zsub(DIMS, dims, tmp, kspace2, tmp); md_zfmac2(DIMS, dims, strs, tmp, strs, kspace1, strs1, pattern); md_copy(DIMS, dims, dst, tmp, CFL_SIZE); md_free(tmp); }
static bool test_md_copy(void) { enum { N = 4 }; long dims[N] = { 10, 10, 10, 10 }; complex float* a = md_alloc(N, dims, sizeof(complex float)); md_gaussian_rand(N, dims, a); complex float* b = md_alloc(N, dims, sizeof(complex float)); md_copy(N, dims, b, a, sizeof(complex float)); bool eq = md_compare(N, dims, a, b, sizeof(complex float)); md_free(a); md_free(b); return eq; }
void iter3_irgnm(iter_conf* _conf, void (*frw)(void* _data, float* dst, const float* src), void (*der)(void* _data, float* dst, const float* src), void (*adj)(void* _data, float* dst, const float* src), void* data2, long N, float* dst, long M, const float* src) { struct iter3_irgnm_conf* conf = CONTAINER_OF(_conf, struct iter3_irgnm_conf, base); float* tmp = md_alloc_sameplace(1, MD_DIMS(M), FL_SIZE, src); struct irgnm_s data = { frw, der, adj, data2, tmp, N }; float* x0 = md_alloc_sameplace(1, MD_DIMS(N), FL_SIZE, src); md_copy(1, MD_DIMS(N), x0, dst, FL_SIZE); irgnm(conf->iter, conf->alpha, conf->redu, &data, N, M, select_vecops(src), forward, adjoint, inverse, dst, x0, src); md_free(x0); md_free(tmp); }
int main_normalize(int argc, char* argv[]) { bool l1 = false; l1 = mini_cmdline_bool(argc, argv, 'b', 3, usage_str, help_str); int N = DIMS; long dims[N]; complex float* data = load_cfl(argv[2], N, dims); int flags = atoi(argv[1]); assert(flags >= 0); complex float* out = create_cfl(argv[3], N, dims); md_copy(N, dims, out, data, CFL_SIZE); (l1 ? normalizel1 : normalize)(N, flags, dims, out); unmap_cfl(N, dims, out); exit(0); }
void direct_calib(const long dims[5], complex float* sens, const long caldims[5], const complex float* data) { complex float* tmp = md_alloc(5, caldims, CFL_SIZE); assert(1 == caldims[4]); assert(1 == dims[4]); md_copy(5, caldims, tmp, data, CFL_SIZE); // apply Kaiser-Bessel Window beta=4 for (int z = 0; z < caldims[2]; z++) for (int y = 0; y < caldims[1]; y++) for (int x = 0; x < caldims[0]; x++) for (int c = 0; c < caldims[3]; c++) tmp[((c * caldims[2] + z) * caldims[1] + y) * caldims[0] + x] *= kaiser(4., caldims[2], z) * kaiser(4., caldims[1], y) * kaiser(4., caldims[0], x); md_resize_center(5, dims, sens, caldims, tmp, CFL_SIZE); ifftc(5, dims, 7, sens, sens); long dims1[5]; md_select_dims(5, ~MD_BIT(COIL_DIM), dims1, dims); complex float* img = md_alloc(5, dims1, CFL_SIZE); md_zrss(5, dims, COIL_FLAG, img, sens); #if 1 long T = md_calc_size(5, dims1); for (int i = 0; i < T; i++) for (int j = 0; j < dims[COIL_DIM]; j++) sens[j * T + i] *= (cabs(img[i]) == 0.) ? 0. : (1. / cabs(img[i])); #endif md_free(img); }
void iwt(unsigned int N, unsigned int flags, const long shifts[N], const long dims[N], const long ostr[N], complex float* out, const complex float* in, const long minsize[N], const long flen, const float filter[2][2][flen]) { if (0 == flags) { if (out != in) md_copy2(N, dims, ostr, out, ostr, in, CFL_SIZE); return; } unsigned long coeffs = wavelet_coeffs(N, flags, dims, minsize, flen); long wdims[2 * N]; wavelet_dims(N, flags, wdims, dims, flen); long istr[2 * N]; md_calc_strides(2 * N, istr, wdims, CFL_SIZE); long offset = coeffs - md_calc_size(2 * N, wdims); debug_printf(DP_DEBUG4, "%d %ld %ld\n", flags, coeffs, offset); complex float* tmp = md_alloc_sameplace(2 * N, wdims, CFL_SIZE, out); md_copy(2 * N, wdims, tmp, in + offset, CFL_SIZE); long shifts0[N]; for (unsigned int i = 0; i < N; i++) shifts0[i] = 0; // fix me we need temp storage iwt(N, wavelet_filter_flags(N, flags, wdims, minsize), shifts0, wdims, istr, tmp, in, minsize, flen, filter); iwtN(N, flags, shifts, dims, ostr, out, istr, tmp, flen, filter); md_free(tmp); }
/** * Operator interface for a true matrix: * out = mat * in * in: [x x x x 1 x x K x x] * mat: [x x x x T x x K x x] * out: [x x x x T x x 1 x x] * where the x's are arbitrary dimensions and T and K may be transposed * * use this interface if K == 1 or T == 1 * * @param N number of dimensions * @param out_dims output dimensions after applying the matrix (codomain) * @param in_dims input dimensions to apply the matrix (domain) * @param T_dim dimension corresponding to the rows of A * @param K_dim dimension corresponding to the columns of A * @param matrix matrix data */ struct linop_s* linop_matrix_altcreate(unsigned int N, const long out_dims[N], const long in_dims[N], const unsigned int T_dim, const unsigned int K_dim, const complex float* matrix) { long matrix_dims[N]; md_singleton_dims(N, matrix_dims); matrix_dims[K_dim] = in_dims[K_dim]; matrix_dims[T_dim] = out_dims[T_dim]; unsigned int T = out_dims[T_dim]; unsigned int K = in_dims[K_dim]; PTR_ALLOC(long[N], max_dims); for (unsigned int i = 0; i < N; i++) { if ((in_dims[i] > 1) && (out_dims[i] == 1)) { (*max_dims)[i] = in_dims[i]; } else if ((in_dims[i] == 1) && (out_dims[i] > 1)) { (*max_dims)[i] = out_dims[i]; } else { assert(in_dims[i] == out_dims[i]); (*max_dims)[i] = in_dims[i]; } } complex float* mat = md_alloc_sameplace(N, matrix_dims, CFL_SIZE, matrix); complex float* matc = md_alloc_sameplace(N, matrix_dims, CFL_SIZE, matrix); md_copy(N, matrix_dims, mat, matrix, CFL_SIZE); md_zconj(N, matrix_dims, matc, mat); complex float* gram = NULL; const struct iovec_s* gram_iovec = compute_gram_matrix(N, T_dim, T, K_dim, K, &gram, matrix_dims, matrix); PTR_ALLOC(struct operator_matrix_s, data); SET_TYPEID(operator_matrix_s, data); data->mat_iovec = iovec_create(N, matrix_dims, CFL_SIZE); data->mat_gram_iovec = gram_iovec; data->max_dims = *max_dims; data->mat = mat; data->mat_conj = matc; data->mat_gram = gram; data->K_dim = K_dim; data->T_dim = T_dim; data->K = K; data->T = T; data->domain_iovec = iovec_create(N, in_dims, CFL_SIZE); data->codomain_iovec = iovec_create(N, out_dims, CFL_SIZE); return linop_create(N, out_dims, N, in_dims, CAST_UP(PTR_PASS(data)), linop_matrix_apply, linop_matrix_apply_adjoint, linop_matrix_apply_normal, NULL, linop_matrix_del); }
/** * Compute the Gram matrix, A^H A. * Stores the result in @param gram, which is allocated by the function * Returns: iovec_s corresponding to the gram matrix dimensions * * @param N number of dimensions * @param T_dim dimension corresponding to the rows of A * @param T number of rows of A (codomain) * @param K_dim dimension corresponding to the columns of A * @param K number of columns of A (domain) * @param gram store the result (allocated by this function) * @param matrix_dims dimensions of A * @param matrix matrix data */ const struct iovec_s* compute_gram_matrix(unsigned int N, unsigned int T_dim, unsigned int T, unsigned int K_dim, unsigned int K, complex float** gram, const long matrix_dims[N], const complex float* matrix) { // FIXME this can certainly be simplfied... // Just be careful to consider the case where the data passed to the operator is a subset of a bigger array // B_dims = [T K 1] or [K T 1] // C_dims = [T 1 K] or [1 T K] // A_dims = [1 K K] or [K 1 K] // after: gram_dims = [1 K1 K2] --> [K2 K1 1] or [K1 1 K2] --> [K1 K2 1] long A_dims[N + 1]; long B_dims[N + 1]; long C_dims[N + 1]; long fake_gram_dims[N + 1]; long A_str[N + 1]; long B_str[N + 1]; long C_str[N + 1]; long max_dims[N + 1]; md_singleton_dims(N + 1, A_dims); md_singleton_dims(N + 1, B_dims); md_singleton_dims(N + 1, C_dims); md_singleton_dims(N + 1, fake_gram_dims); md_singleton_dims(N + 1, max_dims); A_dims[K_dim] = K; A_dims[N] = K; B_dims[T_dim] = T; B_dims[K_dim] = K; C_dims[T_dim] = T; C_dims[N] = K; max_dims[T_dim] = T; max_dims[K_dim] = K; max_dims[N] = K; fake_gram_dims[T_dim] = K; fake_gram_dims[K_dim] = K; md_calc_strides(N + 1, A_str, A_dims, CFL_SIZE); md_calc_strides(N + 1, B_str, B_dims, CFL_SIZE); md_calc_strides(N + 1, C_str, C_dims, CFL_SIZE); complex float* tmpA = md_alloc_sameplace(N + 1 , A_dims, CFL_SIZE, matrix); complex float* tmpB = md_alloc_sameplace(N + 1, B_dims, CFL_SIZE, matrix); complex float* tmpC = md_alloc_sameplace(N + 1, C_dims, CFL_SIZE, matrix); md_copy(N, matrix_dims, tmpB, matrix, CFL_SIZE); //md_copy(N, matrix_dims, tmpC, matrix, CFL_SIZE); md_transpose(N + 1, K_dim, N, C_dims, tmpC, B_dims, tmpB, CFL_SIZE); md_clear(N + 1, A_dims, tmpA, CFL_SIZE); md_zfmacc2(N + 1, max_dims, A_str, tmpA, B_str, tmpB, C_str, tmpC); *gram = md_alloc_sameplace(N, fake_gram_dims, CFL_SIZE, matrix); md_transpose(N + 1, T_dim, N, fake_gram_dims, *gram, A_dims, tmpA, CFL_SIZE); const struct iovec_s* s = iovec_create(N, fake_gram_dims, CFL_SIZE); md_free(tmpA); md_free(tmpB); md_free(tmpC); return s; }
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); }