float* create_coo(const char* name, unsigned int D, const long dims[D]) { int ofd; if (-1 == (ofd = open(name, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR))) io_error("Creating coo file %s", name); if (-1 == write_coo(ofd, D, dims)) io_error("Creating coo file %s", name); long T = md_calc_size(D, dims) * sizeof(float); void* addr; if (NULL == (addr = create_data(ofd, 4096, T))) io_error("Creating coo file %s", name); if (-1 == close(ofd)) io_error("Creating coo file %s", name); return (float*)addr; }
const struct operator_p_s* prox_normaleq_create(const struct linop_s* op, const complex float* y) { PTR_ALLOC(struct prox_normaleq_data, pdata); SET_TYPEID(prox_normaleq_data, pdata); PTR_ALLOC(struct iter_conjgrad_conf, cgconf); *cgconf = iter_conjgrad_defaults; cgconf->maxiter = 10; cgconf->l2lambda = 0; pdata->cgconf = PTR_PASS(cgconf); pdata->op = op; pdata->size = 2 * md_calc_size(linop_domain(op)->N, linop_domain(op)->dims); pdata->adj = md_alloc_sameplace(1, &(pdata->size), FL_SIZE, y); linop_adjoint_iter((struct linop_s*)op, pdata->adj, (const float*)y); return operator_p_create(linop_domain(op)->N, linop_domain(op)->dims, linop_domain(op)->N, linop_domain(op)->dims, CAST_UP(PTR_PASS(pdata)), prox_normaleq_apply, prox_normaleq_del); }
extern gboolean refresh_callback(GtkWidget *widget, gpointer data) { struct view_s* v = data; v->invalid = true; long size = md_calc_size(DIMS, v->dims); double max = 0.; for (long j = 0; j < size; j++) if (max < cabsf(v->data[j])) max = cabsf(v->data[j]); if (0. == max) max = 1.; v->max = max; update_view(v); return FALSE; }
void noir_adj(struct noir_data* data, complex float* dst, const complex float* src) { long split = md_calc_size(DIMS, data->imgs_dims); md_zmulc2(DIMS, data->sign_dims, data->sign_strs, data->tmp, data->data_strs, src, data->ptrn_strs, data->pattern); ifft(DIMS, data->sign_dims, FFT_FLAGS, data->tmp, data->tmp); // we should move it to the end, but fft scaling is applied so this would be need to moved into data->xn or weights maybe? md_zmulc2(DIMS, data->sign_dims, data->sign_strs, data->tmp, data->sign_strs, data->tmp, data->mask_strs, data->mask); md_clear(DIMS, data->coil_dims, dst + split, CFL_SIZE); md_zfmacc2(DIMS, data->sign_dims, data->coil_strs, dst + split, data->sign_strs, data->tmp, data->imgs_strs, data->xn); noir_back_coils(data, dst + split, dst + split); md_clear(DIMS, data->imgs_dims, dst, CFL_SIZE); md_zfmacc2(DIMS, data->sign_dims, data->imgs_strs, dst, data->sign_strs, data->tmp, data->coil_strs, data->sens); if (data->rvc) md_zreal(DIMS, data->imgs_dims, dst, dst); }
static void linop_matrix_apply_normal(const linop_data_t* _data, complex float* dst, const complex float* src) { const struct operator_matrix_s* data = CAST_DOWN(operator_matrix_s, _data); unsigned int N = data->mat_iovec->N; // FIXME check all the cases where computation can be done with blas //debug_printf(DP_DEBUG1, "compute normal\n"); if (cgemm_forward_standard(data)) { long max_dims_gram[N]; md_copy_dims(N, max_dims_gram, data->domain_iovec->dims); max_dims_gram[data->T_dim] = data->K; long tmp_dims[N]; long tmp_str[N]; md_copy_dims(N, tmp_dims, max_dims_gram); tmp_dims[data->K_dim] = 1; md_calc_strides(N, tmp_str, tmp_dims, CFL_SIZE); complex float* tmp = md_alloc_sameplace(N, data->domain_iovec->dims, CFL_SIZE, dst); md_clear(N, data->domain_iovec->dims, tmp, CFL_SIZE); md_zfmac2(N, max_dims_gram, tmp_str, tmp, data->domain_iovec->strs, src, data->mat_gram_iovec->strs, data->mat_gram); md_transpose(N, data->T_dim, data->K_dim, data->domain_iovec->dims, dst, tmp_dims, tmp, CFL_SIZE); md_free(tmp); } else { long L = md_calc_size(data->T_dim, data->domain_iovec->dims); blas_cgemm('N', 'T', L, data->K, data->K, 1., L, (const complex float (*)[])src, data->K, (const complex float (*)[])data->mat_gram, 0., L, (complex float (*)[])dst); } }
float nucnorm_blockproc( const void* _data, const long blkdims[DIMS], complex float* dst, const complex float* src ) { UNUSED(dst); const struct svthresh_blockproc_data* data = (const struct svthresh_blockproc_data*) _data; long M = 1; long N = md_calc_size( DIMS, blkdims ); for ( unsigned int i = 0; i < DIMS; i++ ) { if (MD_IS_SET(data->mflags, i)) { M *= blkdims[i]; N /= blkdims[i]; } } float G = sqrtf(M) + sqrtf(N); return G * nuclearnorm(M, N, src); }
static void fftmod2_r(unsigned int N, const long dims[N], unsigned long flags, const long ostrs[N], complex float* dst, const long istrs[N], const complex float* src, bool inv, double phase) { if (0 == flags) { md_zsmul2(N, dims, ostrs, dst, istrs, src, cexp(M_PI * 2.i * (inv ? -phase : phase))); return; } /* this will also currently be slow on the GPU because we do not * support strides there on the lowest level */ unsigned int i = N - 1; while (!MD_IS_SET(flags, i)) i--; #if 1 // If there is only one dimensions left and it is the innermost // which is contiguous optimize using md_zfftmod2 if ((0u == MD_CLEAR(flags, i)) && (1 == md_calc_size(i, dims)) && (CFL_SIZE == ostrs[i]) && (CFL_SIZE == istrs[i])) { md_zfftmod2(N - i, dims + i, ostrs + i, dst, istrs + i, src, inv, phase); return; } #endif long tdims[N]; md_select_dims(N, ~MD_BIT(i), tdims, dims); #pragma omp parallel for for (int j = 0; j < dims[i]; j++) fftmod2_r(N, tdims, MD_CLEAR(flags, i), ostrs, (void*)dst + j * ostrs[i], istrs, (void*)src + j * istrs[i], inv, phase + fftmod_phase(dims[i], j)); }
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); }
int main(int argc, char *argv[]) { MATFile *mat; const char* name = NULL; const mwSize* dims; if (argc != 2) { fprintf(stderr, "Usage: %s file.mat\n", argv[0]); exit(1); } if (NULL == (mat = matOpen(argv[1], "r"))) exit(1); mxArray* ar; while (NULL != (ar = matGetNextVariable(mat, &name))) { int ndim = (int)mxGetNumberOfDimensions(ar); dims = mxGetDimensions(ar); bool cmp = mxIsComplex(ar); bool dbl = mxIsDouble(ar); printf("%s: [ ", name); if ((!cmp) || (!dbl)) { printf("not complex double\n"); mxDestroyArray(ar); continue; } long ldims[ndim]; for (int i = 0; i < ndim; i++) ldims[i] = dims[i]; for (int i = 0; i < ndim; i++) printf("%ld ", ldims[i]); char outname[256]; snprintf(outname, 256, "%s_%s", strtok(argv[1], "."), name); complex float* buf = create_cfl(outname, ndim, ldims); double* re = mxGetPr(ar); double* im = mxGetPi(ar); size_t size = md_calc_size(ndim, ldims); for (unsigned long i = 0; i < size; i++) buf[i] = re[i] + 1.i * im[i]; printf("] -> %s\n", outname); unmap_cfl(ndim, ldims, buf); mxDestroyArray(ar); } matClose(mat); }
void overlapandsave2HB(const struct vec_ops* ops, int N, unsigned int flags, const long blk[N], const long dims1[N], complex float* dst, const long odims[N], const complex float* src1, const long dims2[N], const complex float* src2, const long mdims[N], const complex float* msk) { long dims1B[N]; long tdims[2 * N]; long nodims[2 * N]; long ndims2[2 * N]; long nmdims[2 * N]; int e = N; for (int i = 0; i < N; i++) { if (MD_IS_SET(flags, i)) { assert(1 == dims2[i] % 2); assert(0 == blk[i] % 2); assert(0 == dims1[i] % 2); assert(0 == odims[i] % blk[i]); assert(0 == dims1[i] % blk[i]); assert(dims1[i] == odims[i]); assert(dims2[i] <= blk[i]); assert(dims1[i] >= dims2[i]); assert((1 == mdims[i]) || (mdims[i] == dims1[i])); // blocked output nodims[e] = odims[i] / blk[i]; nodims[i] = blk[i]; // expanded temporary storage tdims[e] = dims1[i] / blk[i]; tdims[i] = blk[i] + dims2[i] - 1; // blocked input // ---|---,---,---|--- // + +++ + // + +++ + if (1 == mdims[i]) { nmdims[2 * i + 1] = 1; nmdims[2 * i + 1] = 1; } else { nmdims[2 * i + 1] = mdims[i] / blk[i]; nmdims[2 * i + 0] = blk[i]; } // resized input // minimal padding dims1B[i] = dims1[i] + (dims2[i] - 1); // kernel ndims2[e] = 1; ndims2[i] = dims2[i]; e++; } else { nodims[i] = odims[i]; tdims[i] = dims1[i]; nmdims[2 * i + 1] = 1; nmdims[2 * i + 0] = mdims[i]; dims1B[i] = dims1[i]; ndims2[i] = dims2[i]; } } int NE = e; // long S = md_calc_size(N, dims1B, 1); long str1[NE]; long str1B[N]; md_calc_strides(N, str1B, dims1B, sizeof(complex float)); e = N; for (int i = 0; i < N; i++) { str1[i] = str1B[i]; if (MD_IS_SET(flags, i)) str1[e++] = str1B[i] * blk[i]; } assert(NE == e); long str2[NE]; md_calc_strides(NE, str2, tdims, sizeof(complex float)); long ostr[NE]; long mstr[NE]; long mstrB[2 * N]; md_calc_strides(NE, ostr, nodims, sizeof(complex float)); md_calc_strides(2 * N, mstrB, nmdims, sizeof(complex float)); e = N; for (int i = 0; i < N; i++) { mstr[i] = mstrB[2 * i + 0]; if (MD_IS_SET(flags, i)) mstr[e++] = mstrB[2 * i + 1]; } assert(NE == e); // we can loop here assert(NE == N + 3); assert(1 == ndims2[N + 0]); assert(1 == ndims2[N + 1]); assert(1 == ndims2[N + 2]); assert(tdims[N + 0] == nodims[N + 0]); assert(tdims[N + 1] == nodims[N + 1]); assert(tdims[N + 2] == nodims[N + 2]); long R = md_calc_size(N, nodims); long T = md_calc_size(N, tdims); //complex float* src1C = xmalloc(S * sizeof(complex float)); complex float* src1C = dst; md_clear(N, dims1B, src1C, CFL_SIZE); // must be done here #pragma omp parallel for collapse(3) for (int k = 0; k < nodims[N + 2]; k++) { for (int j = 0; j < nodims[N + 1]; j++) { for (int i = 0; i < nodims[N + 0]; i++) { complex float* tmp = (complex float*)ops->allocate(2 * T); complex float* tmpX = (complex float*)ops->allocate(2 * R); long off1 = str1[N + 0] * i + str1[N + 1] * j + str1[N + 2] * k; long off2 = mstr[N + 0] * i + mstr[N + 1] * j + mstr[N + 2] * k; long off3 = ostr[N + 0] * i + ostr[N + 1] * j + ostr[N + 2] * k; md_zmul2(N, nodims, ostr, tmpX, ostr, ((const void*)src1) + off3, mstr, ((const void*)msk) + off2); convH(N, flags, CONV_VALID, CONV_SYMMETRIC, tdims, tmp, nodims, tmpX, ndims2, src2); #pragma omp critical md_zadd2(N, tdims, str1, ((void*)src1C) + off1, str1, ((void*)src1C) + off1, str2, tmp); ops->del((void*)tmpX); ops->del((void*)tmp); }}} }
/* calculate point-wise maps * */ void eigenmaps(const long out_dims[DIMS], complex float* optr, complex float* eptr, const complex float* imgcov2, const long msk_dims[3], const bool* msk, bool orthiter, bool ecal_usegpu) { #ifdef USE_CUDA if (ecal_usegpu) { //FIXME cuda version should be able to return sensitivities for a subset of image-space points assert(!msk); eigenmapscu(out_dims, optr, eptr, imgcov2); return; } #else assert(!ecal_usegpu); #endif long channels = out_dims[3]; long maps = out_dims[4]; assert(DIMS >= 5); assert(1 == md_calc_size(DIMS - 5, out_dims + 5)); assert(maps <= channels); long xx = out_dims[0]; long yy = out_dims[1]; long zz = out_dims[2]; float scale = 1.; // for some reason, not if (msk_dims) { assert(msk_dims[0] == xx); assert(msk_dims[1] == yy); assert(msk_dims[2] == zz); } md_clear(5, out_dims, optr, CFL_SIZE); #pragma omp parallel for collapse(3) for (long k = 0; k < zz; k++) { for (long j = 0; j < yy; j++) { for (long i = 0; i < xx; i++) { if (!msk || msk[i + xx * (j + yy * k)]) { float val[channels]; complex float cov[channels][channels]; complex float tmp[channels * (channels + 1) / 2]; for (long l = 0; l < channels * (channels + 1) / 2; l++) tmp[l] = imgcov2[((l * zz + k) * yy + j) * xx + i] / scale; unpack_tri_matrix(channels, cov, tmp); if (orthiter) eigen_herm3(maps, channels, val, cov); else lapack_eig(channels, val, cov); for (long u = 0; u < maps; u++) { long ru = (orthiter ? maps : channels) - 1 - u; for (long v = 0; v < channels; v++) optr[((((u * channels + v) * zz + k) * yy + j) * xx + i)] = cov[ru][v]; if (NULL != eptr) eptr[((u * zz + k) * yy + j) * xx + i] = val[ru]; } } } } } }
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); }
void calib2(const struct ecalib_conf* conf, const long out_dims[DIMS], complex float* out_data, complex float* eptr, unsigned int SN, float svals[SN], const long calreg_dims[DIMS], const complex float* data, const long msk_dims[3], const bool* msk) { long channels = calreg_dims[3]; long maps = out_dims[4]; assert(calreg_dims[3] == out_dims[3]); assert(maps <= channels); assert(1 == md_calc_size(DIMS - 5, out_dims + 5)); assert(1 == md_calc_size(DIMS - 5, calreg_dims + 5)); complex float rot[channels][channels]; if (conf->rotphase) { long scc_dims[DIMS] = MD_INIT_ARRAY(DIMS, 1); scc_dims[COIL_DIM] = channels; scc_dims[MAPS_DIM] = channels; scc(scc_dims, &rot[0][0], calreg_dims, data); } else { for (unsigned int i = 0; i < channels; i++) for (unsigned int j = 0; j < channels; j++) rot[i][j] = (i == j) ? 1. : 0.; } long cov_dims[4]; calone_dims(conf, cov_dims, channels); complex float* imgcov = md_alloc(4, cov_dims, CFL_SIZE); calone(conf, cov_dims, imgcov, SN, svals, calreg_dims, data); caltwo(conf, out_dims, out_data, eptr, cov_dims, imgcov, msk_dims, msk); /* Intensity and phase normalization similar as proposed * for adaptive combine (Walsh's method) in * Griswold et al., ISMRM 10:2410 (2002) */ if (conf->intensity) { debug_printf(DP_DEBUG1, "Normalize...\n"); /* I think the reason this works is because inhomogeneity usually * comes from only a few coil elements which are close. The l1-norm * is more resilient against such outliers. -- Martin */ normalizel1(DIMS, COIL_FLAG, out_dims, out_data); md_zsmul(DIMS, out_dims, out_data, out_data, sqrtf((float)channels)); } debug_printf(DP_DEBUG1, "Crop maps... (%.2f)\n", conf->crop); crop_sens(out_dims, out_data, conf->softcrop, conf->crop, eptr); debug_printf(DP_DEBUG1, "Fix phase...\n"); // rotate the the phase with respect to the first principle component fixphase2(DIMS, out_dims, COIL_DIM, rot[0], out_data, out_data); md_free(imgcov); }
void iter2_niht(iter_conf* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s* prox_ops[D], const struct linop_s* ops[D], const float* biases[D], const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, struct iter_monitor_s* monitor) { UNUSED(xupdate_op); UNUSED(biases); assert(D == 1); auto conf = CAST_DOWN(iter_niht_conf, _conf); struct niht_conf_s niht_conf = { .maxiter = conf->maxiter, .N = size, .trans = 0, .do_warmstart = conf->do_warmstart, }; struct niht_transop trans; if (NULL != ops) { trans.forward = OPERATOR2ITOP(ops[0]->forward); trans.adjoint = OPERATOR2ITOP(ops[0]->adjoint); trans.N = 2 * md_calc_size(linop_codomain(ops[0])->N, linop_codomain(ops[0])->dims); niht_conf.trans = 1; } float eps = md_norm(1, MD_DIMS(size), image_adj); if (checkeps(eps)) goto cleanup; niht_conf.epsilon = eps * conf->tol; niht(&niht_conf, &trans, select_vecops(image_adj), OPERATOR2ITOP(normaleq_op), OPERATOR_P2ITOP(prox_ops[0]), image, image_adj, monitor); cleanup: ; } void iter2_call_iter(iter_conf* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s* prox_ops[D], const struct linop_s* ops[D], const float* biases[D], const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, struct iter_monitor_s* monitor) { assert(D <= 1); assert(NULL == ops); assert(NULL == biases); UNUSED(xupdate_op); auto it = CAST_DOWN(iter_call_s, _conf); it->fun(it->_conf, normaleq_op, (1 == D) ? prox_ops[0] : NULL, size, image, image_adj, monitor); }
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); }
/* O I M G * 1 1 1 1 - not used * 1 1 A ! - forbidden * 1 A 1 ! - forbidden * A 1 1 ! - forbidden * A A 1 1 - replicated * A 1 A 1 - output * 1 A A A/A - input * A A A A - batch */ static struct operator_matrix_s* linop_matrix_priv2(unsigned int N, const long out_dims[N], const long in_dims[N], const long matrix_dims[N], const complex float* matrix) { // to get assertions and cost estimate long max_dims[N]; md_tenmul_dims(N, max_dims, out_dims, in_dims, matrix_dims); PTR_ALLOC(struct operator_matrix_s, data); SET_TYPEID(operator_matrix_s, data); data->N = N; PTR_ALLOC(long[N], out_dims1); md_copy_dims(N, *out_dims1, out_dims); data->out_dims = *PTR_PASS(out_dims1); PTR_ALLOC(long[N], mat_dims1); md_copy_dims(N, *mat_dims1, matrix_dims); data->mat_dims = *PTR_PASS(mat_dims1); PTR_ALLOC(long[N], in_dims1); md_copy_dims(N, *in_dims1, in_dims); data->in_dims = *PTR_PASS(in_dims1); complex float* mat = md_alloc(N, matrix_dims, CFL_SIZE); md_copy(N, matrix_dims, mat, matrix, CFL_SIZE); data->mat = mat; data->mat_gram = NULL; #ifdef USE_CUDA data->mat_gpu = NULL; data->mat_gram_gpu = NULL; #endif #if 1 // pre-multiply gram matrix (if there is a cost reduction) unsigned long out_flags = md_nontriv_dims(N, out_dims); unsigned long in_flags = md_nontriv_dims(N, in_dims); unsigned long del_flags = in_flags & ~out_flags; unsigned long new_flags = out_flags & ~in_flags; /* we double (again) for the gram matrix */ PTR_ALLOC(long[2 * N], mat_dims2); PTR_ALLOC(long[2 * N], in_dims2); PTR_ALLOC(long[2 * N], gmt_dims2); PTR_ALLOC(long[2 * N], gin_dims2); PTR_ALLOC(long[2 * N], grm_dims2); PTR_ALLOC(long[2 * N], gout_dims2); shadow_dims(N, *gmt_dims2, matrix_dims); shadow_dims(N, *mat_dims2, matrix_dims); shadow_dims(N, *in_dims2, in_dims); shadow_dims(N, *gout_dims2, in_dims); shadow_dims(N, *gin_dims2, in_dims); shadow_dims(N, *grm_dims2, matrix_dims); /* move removed input dims into shadow position * for the gram matrix can have an output there */ for (unsigned int i = 0; i < N; i++) { if (MD_IS_SET(del_flags, i)) { assert((*mat_dims2)[2 * i + 0] == (*in_dims2)[2 * i + 0]); (*mat_dims2)[2 * i + 1] = (*mat_dims2)[2 * i + 0]; (*mat_dims2)[2 * i + 0] = 1; (*in_dims2)[2 * i + 1] = (*gin_dims2)[2 * i + 0]; (*in_dims2)[2 * i + 0] = 1; } } for (unsigned int i = 0; i < N; i++) { if (MD_IS_SET(new_flags, i)) { (*grm_dims2)[2 * i + 0] = 1; (*grm_dims2)[2 * i + 1] = 1; } if (MD_IS_SET(del_flags, i)) { (*gout_dims2)[2 * i + 1] = (*gin_dims2)[2 * i + 0]; (*gout_dims2)[2 * i + 0] = 1; (*grm_dims2)[2 * i + 0] = in_dims[i]; (*grm_dims2)[2 * i + 1] = in_dims[i]; } } long gmx_dims[2 * N]; md_tenmul_dims(2 * N, gmx_dims, *gout_dims2, *gin_dims2, *grm_dims2); long mult_mat = md_calc_size(N, max_dims); long mult_gram = md_calc_size(2 * N, gmx_dims); if (mult_gram < 2 * mult_mat) { // FIXME: rethink debug_printf(DP_DEBUG2, "Gram matrix: 2x %ld vs %ld\n", mult_mat, mult_gram); complex float* mat_gram = md_alloc(2 * N, *grm_dims2, CFL_SIZE); md_ztenmulc(2 * N, *grm_dims2, mat_gram, *gmt_dims2, matrix, *mat_dims2, matrix); data->mat_gram = mat_gram; } PTR_FREE(gmt_dims2); PTR_FREE(mat_dims2); PTR_FREE(in_dims2); data->gin_dims = *PTR_PASS(gin_dims2); data->gout_dims = *PTR_PASS(gout_dims2); data->grm_dims = *PTR_PASS(grm_dims2); #else data->gin_dims = NULL; data->gout_dims = NULL; data->grm_dims = NULL; #endif return PTR_PASS(data); }
int main_reshape(int argc, char* argv[]) { int c; while (-1 != (c = getopt(argc, argv, "h"))) { switch (c) { 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]); unsigned int n = bitcount(flags); assert((int)n + 3 == argc - optind); long in_dims[DIMS]; long in_strs[DIMS]; long out_dims[DIMS]; long out_strs[DIMS]; complex float* in_data = load_cfl(argv[optind + n + 1], 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[optind + j++ + 1]); 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[optind + n + 2], 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); }
/* * Low rank threhsolding for arbitrary block sizes */ static void lrthresh_apply(const operator_data_t* _data, float mu, complex float* dst, const complex float* src) { struct lrthresh_data_s* data = CAST_DOWN(lrthresh_data_s, _data); float lambda = mu * data->lambda; long strs1[DIMS]; md_calc_strides(DIMS, strs1, data->dims_decom, 1); //#pragma omp parallel for for (int l = 0; l < data->levels; l++) { complex float* dstl = dst + l * strs1[LEVEL_DIM]; const complex float* srcl = src + l * strs1[LEVEL_DIM]; long blkdims[DIMS]; long shifts[DIMS]; long unshifts[DIMS]; long zpad_dims[DIMS]; long M = 1; for (unsigned int i = 0; i < DIMS; i++) { blkdims[i] = data->blkdims[l][i]; zpad_dims[i] = (data->dims[i] + blkdims[i] - 1) / blkdims[i]; zpad_dims[i] *= blkdims[i]; if (MD_IS_SET(data->mflags, i)) M *= blkdims[i]; if (data->randshift) shifts[i] = rand_lim(MIN(blkdims[i] - 1, zpad_dims[i] - blkdims[i])); else shifts[i] = 0; unshifts[i] = -shifts[i]; } long zpad_strs[DIMS]; md_calc_strides(DIMS, zpad_strs, zpad_dims, CFL_SIZE); long blk_size = md_calc_size(DIMS, blkdims); long img_size = md_calc_size(DIMS, zpad_dims); long N = blk_size / M; long B = img_size / blk_size; if (data->noise && (l == data->levels - 1)) { M = img_size; N = 1; B = 1; } complex float* tmp = md_alloc_sameplace(DIMS, zpad_dims, CFL_SIZE, dst); md_circ_ext(DIMS, zpad_dims, tmp, data->dims, srcl, CFL_SIZE); md_circ_shift(DIMS, zpad_dims, shifts, tmp, tmp, CFL_SIZE); long mat_dims[2]; basorati_dims(DIMS, mat_dims, blkdims, zpad_dims); complex float* tmp_mat = md_alloc_sameplace(2, mat_dims, CFL_SIZE, dst); // Reshape image into a blk_size x number of blocks matrix basorati_matrix(DIMS, blkdims, mat_dims, tmp_mat, zpad_dims, zpad_strs, tmp); batch_svthresh(M, N, mat_dims[1], lambda * GWIDTH(M, N, B), *(complex float (*)[mat_dims[1]][M][N])tmp_mat); // for ( int b = 0; b < mat_dims[1]; b++ ) // svthresh(M, N, lambda * GWIDTH(M, N, B), tmp_mat, tmp_mat); basorati_matrixH(DIMS, blkdims, zpad_dims, zpad_strs, tmp, mat_dims, tmp_mat); md_circ_shift(DIMS, zpad_dims, unshifts, tmp, tmp, CFL_SIZE); md_resize(DIMS, data->dims, dstl, zpad_dims, tmp, CFL_SIZE); md_free(tmp); md_free(tmp_mat); } }
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 {
void iter2_admm(void* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s** prox_ops, const struct linop_s** ops, const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, const float* image_truth, void* obj_eval_data, float (*obj_eval)(const void*, const float*)) { struct iter_admm_conf* conf = _conf; struct admm_plan_s admm_plan = { .maxiter = conf->maxiter, .maxitercg = conf->maxitercg, .rho = conf->rho, .image_truth = image_truth, .num_funs = D, .do_warmstart = conf->do_warmstart, .dynamic_rho = conf->dynamic_rho, .hogwild = conf->hogwild, .ABSTOL = conf->ABSTOL, .RELTOL = conf->RELTOL, .alpha = conf->alpha, .tau = conf->tau, .mu = conf->mu, .fast = conf->fast, }; struct admm_op a_ops[D]; struct admm_prox_op a_prox_ops[D]; for (unsigned int i = 0; i < D; i++) { a_ops[i].forward = linop_forward_iter; a_ops[i].normal = linop_normal_iter; a_ops[i].adjoint = linop_adjoint_iter; a_ops[i].data = (void*)ops[i]; a_prox_ops[i].prox_fun = operator_p_iter; a_prox_ops[i].data = (void*)prox_ops[i]; } admm_plan.ops = a_ops; admm_plan.prox_ops = a_prox_ops; admm_plan.xupdate_fun = operator_p_iter; admm_plan.xupdate_data = (void*)xupdate_op; struct admm_history_s admm_history; long z_dims[D]; for (unsigned int i = 0; i < D; i++) z_dims[i] = 2 * md_calc_size(linop_codomain(ops[i])->N, linop_codomain(ops[i])->dims); if (NULL != image_adj) { float eps = md_norm(1, MD_DIMS(size), image_adj); if (checkeps(eps)) goto cleanup; } admm(&admm_history, &admm_plan, admm_plan.num_funs, z_dims, size, (float*)image, image_adj, select_vecops(image), operator_iter, (void*)normaleq_op, obj_eval_data, obj_eval); cleanup: ; } void iter2_pocs(void* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s** prox_ops, const struct linop_s** ops, const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, const float* image_truth, void* obj_eval_data, float (*obj_eval)(const void*, const float*)) { const struct iter_pocs_conf* conf = _conf; assert(NULL == normaleq_op); assert(NULL == ops); assert(NULL == image_adj); UNUSED(xupdate_op); UNUSED(image_adj); struct pocs_proj_op proj_ops[D]; for (unsigned int i = 0; i < D; i++) { proj_ops[i].proj_fun = operator_p_iter; proj_ops[i].data = (void*)prox_ops[i]; } pocs(conf->maxiter, D, proj_ops, select_vecops(image), size, image, image_truth, obj_eval_data, obj_eval); } void iter2_call_iter(void* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s** prox_ops, const struct linop_s** ops, const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, const float* image_truth, void* obj_eval_data, float (*obj_eval)(const void*, const float*)) { assert(D <= 1); assert(NULL == ops); UNUSED(xupdate_op); struct iter_call_s* it = _conf; it->fun(it->_conf, normaleq_op, (1 == D) ? prox_ops[0] : NULL, size, image, image_adj, image_truth, obj_eval_data, obj_eval); }
/* * Low rank threhsolding for arbitrary block sizes */ static void lrthresh_apply(const void* _data, float mu, complex float* dst, const complex float* src) { struct lrthresh_data_s* data = (struct lrthresh_data_s*)_data; float lambda = mu * data->lambda; long strs1[DIMS]; md_calc_strides(DIMS, strs1, data->dims_decom, 1); //#pragma omp parallel for for (int l = 0; l < data->levels; l++) { complex float* dstl = dst + l * strs1[LEVEL_DIM]; const complex float* srcl = src + l * strs1[LEVEL_DIM]; // Initialize long blkdims[DIMS]; long shifts[DIMS]; long unshifts[DIMS]; long zpad_dims[DIMS]; long M = 1; for (unsigned int i = 0; i < DIMS; i++) { blkdims[i] = data->blkdims[l][i]; zpad_dims[i] = (data->dims[i] + blkdims[i] - 1) / blkdims[i]; zpad_dims[i] *= blkdims[i]; if (MD_IS_SET(data->mflags, i)) M *= blkdims[i]; if (data->randshift) shifts[i] = rand_lim(MIN(blkdims[i] - 1, zpad_dims[i] - blkdims[i])); else shifts[i] = 0; unshifts[i] = -shifts[i]; } long zpad_strs[DIMS]; md_calc_strides(DIMS, zpad_strs, zpad_dims, CFL_SIZE); long blk_size = md_calc_size( DIMS, blkdims ); long img_size = md_calc_size( DIMS, zpad_dims ); long N = blk_size / M; long B = img_size / blk_size; if (data->noise && (l == data->levels - 1)) { M = img_size; N = 1; B = 1; } // Initialize tmp complex float* tmp_ext; #ifdef USE_CUDA tmp_ext = (data->use_gpu ? md_alloc_gpu : md_alloc)(DIMS, zpad_dims, CFL_SIZE); #else tmp_ext = md_alloc(DIMS, zpad_dims, CFL_SIZE); #endif complex float* tmp; #ifdef USE_CUDA tmp = (data->use_gpu ? md_alloc_gpu : md_alloc)(DIMS, zpad_dims, CFL_SIZE); #else tmp = md_alloc(DIMS, zpad_dims, CFL_SIZE); #endif // Copy to tmp md_circ_ext(DIMS, zpad_dims, tmp_ext, data->dims, srcl, CFL_SIZE); if (data->randshift) md_circ_shift(DIMS, zpad_dims, shifts, tmp, tmp_ext, CFL_SIZE); // Initialize tmp_mat long mat_dims[2]; basorati_dims(DIMS, mat_dims, blkdims, zpad_dims); complex float* tmp_mat; #ifdef USE_CUDA tmp_mat = (data->use_gpu ? md_alloc_gpu : md_alloc)(2, mat_dims, CFL_SIZE); #else tmp_mat = md_alloc(2, mat_dims, CFL_SIZE); #endif // Reshape image into a blk_size x number of blocks matrix basorati_matrix(DIMS, blkdims, mat_dims, tmp_mat, zpad_dims, zpad_strs, tmp); batch_svthresh(M, N, mat_dims[1], lambda * GWIDTH(M, N, B), tmp_mat, tmp_mat); // for ( int b = 0; b < mat_dims[1]; b++ ) // svthresh(M, N, lambda * GWIDTH(M, N, B), tmp_mat, tmp_mat); basorati_matrixH(DIMS, blkdims, zpad_dims, zpad_strs, tmp, mat_dims, tmp_mat); // Copy to tmp if (data->randshift) md_circ_shift(DIMS, zpad_dims, unshifts, tmp_ext, tmp, CFL_SIZE); md_resize(DIMS, data->dims, dstl, zpad_dims, tmp_ext, CFL_SIZE); // Free data md_free(tmp); md_free(tmp_ext); md_free(tmp_mat); } }
void overlapandsave2NE(int N, unsigned int flags, const long blk[N], const long odims[N], complex float* dst, const long dims1[N], complex float* src1, const long dims2[N], complex float* src2, const long mdims[N], complex float* msk) { long dims1B[N]; long tdims[2 * N]; long nodims[2 * N]; long ndims1[2 * N]; long ndims2[2 * N]; long shift[2 * N]; unsigned int nflags = 0; for (int i = 0; i < N; i++) { if (MD_IS_SET(flags, i)) { nflags = MD_SET(nflags, 2 * i); assert(1 == dims2[i] % 2); assert(0 == blk[i] % 2); assert(0 == dims1[i] % 2); assert(0 == odims[i] % blk[i]); assert(0 == dims1[i] % blk[i]); assert(dims1[i] == odims[i]); assert(dims2[i] <= blk[i]); assert(dims1[i] >= dims2[i]); // blocked output nodims[i * 2 + 1] = odims[i] / blk[i]; nodims[i * 2 + 0] = blk[i]; // expanded temporary storage tdims[i * 2 + 1] = dims1[i] / blk[i]; tdims[i * 2 + 0] = blk[i] + dims2[i] - 1; // blocked input // ---|---,---,---|--- // + +++ + // + +++ + // resized input dims1B[i] = dims1[i] + 2 * blk[i]; ndims1[i * 2 + 1] = dims1[i] / blk[i] + 2; // do we need two full blocks? ndims1[i * 2 + 0] = blk[i]; shift[i * 2 + 1] = 0; shift[i * 2 + 0] = blk[i] - (dims2[i] - 1) / 2; // kernel ndims2[i * 2 + 1] = 1; ndims2[i * 2 + 0] = dims2[i]; } else { nodims[i * 2 + 1] = 1; nodims[i * 2 + 0] = odims[i]; tdims[i * 2 + 1] = 1; tdims[i * 2 + 0] = dims1[i]; ndims1[i * 2 + 1] = 1; ndims1[i * 2 + 0] = dims1[i]; shift[i * 2 + 1] = 0; shift[i * 2 + 0] = 0; dims1B[i] = dims1[i]; ndims2[i * 2 + 1] = 1; ndims2[i * 2 + 0] = dims2[i]; } } long R = md_calc_size(N, odims); long T = md_calc_size(2 * N, tdims); long S = md_calc_size(N, dims1B); complex float* src1B = xmalloc(S * sizeof(complex float)); complex float* tmp = xmalloc(T * sizeof(complex float)); complex float* tmpX = xmalloc(R * sizeof(complex float)); long str1[2 * N]; long str2[2 * N]; md_calc_strides(2 * N, str1, ndims1, sizeof(complex float)); md_calc_strides(2 * N, str2, tdims, sizeof(complex float)); long off = md_calc_offset(2 * N, str1, shift); md_resize_center(N, dims1B, src1B, dims1, src1, sizeof(complex float)); // we can loop here md_copy2(2 * N, tdims, str2, tmp, str1, ((void*)src1B) + off, sizeof(complex float)); conv(2 * N, nflags, CONV_VALID, CONV_SYMMETRIC, nodims, tmpX, tdims, tmp, ndims2, src2); long ostr[N]; long mstr[N]; md_calc_strides(N, ostr, odims, sizeof(complex float)); md_calc_strides(N, mstr, mdims, sizeof(complex float)); md_zmul2(N, odims, ostr, tmpX, ostr, tmpX, mstr, msk); convH(2 * N, nflags, CONV_VALID, CONV_SYMMETRIC, tdims, tmp, nodims, tmpX, ndims2, src2); md_clear(N, dims1B, src1B, sizeof(complex float)); md_zadd2(2 * N, tdims, str1, ((void*)src1B) + off, str1, ((void*)src1B) + off, str2, tmp); // md_resize_center(N, dims1, dst, dims1B, src1B, sizeof(complex float)); free(src1B); free(tmpX); free(tmp); }
/** * Efficiently chain two matrix linops by multiplying the actual matrices together. * Stores a copy of the new matrix. * Returns: C = B A * * @param a first matrix (applied to input) * @param b second matrix (applied to output of first matrix) */ struct linop_s* linop_matrix_chain(const struct linop_s* a, const struct linop_s* b) { const struct operator_matrix_s* a_data = CAST_DOWN(operator_matrix_s, linop_get_data(a)); const struct operator_matrix_s* b_data = CAST_DOWN(operator_matrix_s, linop_get_data(b)); // check compatibility assert(linop_codomain(a)->N == linop_domain(b)->N); assert(md_check_compat(linop_codomain(a)->N, 0u, linop_codomain(a)->dims, linop_domain(b)->dims)); unsigned int D = linop_domain(a)->N; unsigned long outB_flags = md_nontriv_dims(D, linop_codomain(b)->dims); unsigned long inB_flags = md_nontriv_dims(D, linop_domain(b)->dims); unsigned long delB_flags = inB_flags & ~outB_flags; unsigned int N = a_data->N; assert(N == 2 * D); long in_dims[N]; md_copy_dims(N, in_dims, a_data->in_dims); long matA_dims[N]; md_copy_dims(N, matA_dims, a_data->mat_dims); long matB_dims[N]; md_copy_dims(N, matB_dims, b_data->mat_dims); long out_dims[N]; md_copy_dims(N, out_dims, b_data->out_dims); for (unsigned int i = 0; i < D; i++) { if (MD_IS_SET(delB_flags, i)) { matA_dims[2 * i + 0] = a_data->mat_dims[2 * i + 1]; matA_dims[2 * i + 1] = a_data->mat_dims[2 * i + 0]; in_dims[2 * i + 0] = a_data->in_dims[2 * i + 1]; in_dims[2 * i + 1] = a_data->in_dims[2 * i + 0]; } } long matrix_dims[N]; md_singleton_dims(N, matrix_dims); unsigned long iflags = md_nontriv_dims(N, in_dims); unsigned long oflags = md_nontriv_dims(N, out_dims); unsigned long flags = iflags | oflags; // we combine a and b and sum over dims not in input or output md_max_dims(N, flags, matrix_dims, matA_dims, matB_dims); debug_printf(DP_DEBUG1, "tensor chain: %ld x %ld -> %ld\n", md_calc_size(N, matA_dims), md_calc_size(N, matB_dims), md_calc_size(N, matrix_dims)); complex float* matrix = md_alloc(N, matrix_dims, CFL_SIZE); debug_print_dims(DP_DEBUG2, N, matrix_dims); debug_print_dims(DP_DEBUG2, N, in_dims); debug_print_dims(DP_DEBUG2, N, matA_dims); debug_print_dims(DP_DEBUG2, N, matB_dims); debug_print_dims(DP_DEBUG2, N, out_dims); md_ztenmul(N, matrix_dims, matrix, matA_dims, a_data->mat, matB_dims, b_data->mat); // priv2 takes our doubled dimensions struct operator_matrix_s* data = linop_matrix_priv2(N, out_dims, in_dims, matrix_dims, matrix); /* although we internally use different dimensions we define the * correct interface */ struct linop_s* c = linop_create(linop_codomain(b)->N, linop_codomain(b)->dims, linop_domain(a)->N, linop_domain(a)->dims, CAST_UP(data), linop_matrix_apply, linop_matrix_apply_adjoint, linop_matrix_apply_normal, NULL, linop_matrix_del); md_free(matrix); return c; }
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); }
void compute_kernels(const struct ecalib_conf* conf, long nskerns_dims[5], complex float** nskerns_ptr, unsigned int SN, float svals[SN], const long caldims[DIMS], const complex float* caldata) { assert(1 == md_calc_size(DIMS - 5, caldims + 5)); nskerns_dims[0] = conf->kdims[0]; nskerns_dims[1] = conf->kdims[1]; nskerns_dims[2] = conf->kdims[2]; nskerns_dims[3] = caldims[3]; long N = md_calc_size(4, nskerns_dims); assert(N > 0); nskerns_dims[4] = N; complex float* nskerns = md_alloc(5, nskerns_dims, CFL_SIZE); *nskerns_ptr = nskerns; complex float (*vec)[N] = xmalloc(N * N * sizeof(complex float)); assert((NULL == svals) || (SN == N)); float* val = (NULL != svals) ? svals : xmalloc(N * FL_SIZE); debug_printf(DP_DEBUG1, "Build calibration matrix and SVD...\n"); #ifdef CALMAT_SVD calmat_svd(conf->kdims, N, vec, val, caldims, caldata); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) #ifndef FLIP nskerns[i * N + j] = (vec[j][i]) * (conf->weighting ? val[i] : 1.); #else nskerns[i * N + j] = (vec[j][N - 1 - i]) * (conf->weighting ? val[N - 1 - i] : 1.); #endif #else covariance_function(conf->kdims, N, vec, caldims, caldata); debug_printf(DP_DEBUG1, "Eigen decomposition... (size: %ld)\n", N); // we could apply Nystroem method here to speed it up float tmp_val[N]; lapack_eig(N, tmp_val, vec); for (int i = 0; i < N; i++) val[i] = sqrtf(tmp_val[N - 1 - i]); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) #ifndef FLIP nskerns[i * N + j] = vec[N - 1 - i][j] * (conf->weighting ? val[i] : 1.); // flip #else nskerns[i * N + j] = vec[i][j] * (conf->weighting ? val[N - 1 - i] : 1.); // flip #endif #endif if (conf->perturb > 0.) { long dims[2] = { N, N }; perturb(dims, nskerns, conf->perturb); } #ifndef FLIP nskerns_dims[4] = number_of_kernels(conf, N, val); #else nskerns_dims[4] = N - number_of_kernels(conf, N, val); #endif if (NULL == svals) free(val); free(vec); }
static void prox_4pt_dfwavelet_thresh(const operator_data_t* _data, float thresh, complex float* out, const complex float* in) { struct prox_4pt_dfwavelet_data* data = CONTAINER_OF(_data, struct prox_4pt_dfwavelet_data, base); bool done = false; long pos[DIMS]; md_set_dims(DIMS, pos, 0); while (!done) { // copy pc md_slice(DIMS, data->slice_flag, pos, data->im_dims, data->pc0, in, CFL_SIZE); pos[data->flow_dim]++; md_slice(DIMS, data->slice_flag, pos, data->im_dims, data->pc1, in, CFL_SIZE); pos[data->flow_dim]++; md_slice(DIMS, data->slice_flag, pos, data->im_dims, data->pc2, in, CFL_SIZE); pos[data->flow_dim]++; md_slice(DIMS, data->slice_flag, pos, data->im_dims, data->pc3, in, CFL_SIZE); pos[data->flow_dim] = 0; // pc to velocity // TODO: Make gpu for (int i = 0; i < md_calc_size(DIMS, data->tim_dims); i++) { data->vx[i] = (data->pc1[i] - data->pc0[i]) / 2; data->vy[i] = (data->pc2[i] - data->pc1[i]) / 2; data->vz[i] = (data->pc3[i] - data->pc2[i]) / 2; data->ph0[i] = (data->pc0[i] + data->pc3[i]) / 2; } // threshold dfwavelet_thresh(data->plan, thresh * data->lambda, thresh* data->lambda, data->vx, data->vy, data->vz, data->vx, data->vy, data->vz); operator_p_apply(data->wthresh_op, thresh, DIMS, data->tim_dims, data->ph0, DIMS, data->tim_dims, data->ph0); // velocity to pc for (int i = 0; i < md_calc_size(DIMS, data->tim_dims ); i++) { data->pc0[i] = (- data->vx[i] - data->vy[i] - data->vz[i] + data->ph0[i]); data->pc1[i] = (+ data->vx[i] - data->vy[i] - data->vz[i] + data->ph0[i]); data->pc2[i] = (+ data->vx[i] + data->vy[i] - data->vz[i] + data->ph0[i]); data->pc3[i] = (+ data->vx[i] + data->vy[i] + data->vz[i] + data->ph0[i]); } // copy pc md_copy_block(DIMS, pos, data->im_dims, out, data->tim_dims, data->pc0, CFL_SIZE); pos[data->flow_dim]++; md_copy_block(DIMS, pos, data->im_dims, out, data->tim_dims, data->pc1, CFL_SIZE); pos[data->flow_dim]++; md_copy_block( DIMS, pos, data->im_dims, out, data->tim_dims, data->pc2, CFL_SIZE ); pos[data->flow_dim]++; md_copy_block( DIMS, pos, data->im_dims, out, data->tim_dims, data->pc3, CFL_SIZE ); pos[data->flow_dim] = 0; // increment pos long carryon = 1; for(unsigned int i = 0; i < DIMS; i++) { if (MD_IS_SET(data->slice_flag & ~MD_BIT(data->flow_dim), i)) { pos[i] += carryon; if (pos[i] < data->im_dims[i]) { carryon = 0; break; } else { carryon = 1; pos[i] = 0; } } } done = carryon; } }
void iter2_admm(iter_conf* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s* prox_ops[D], const struct linop_s* ops[D], const float* biases[D], const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, struct iter_monitor_s* monitor) { auto conf = CAST_DOWN(iter_admm_conf, _conf); struct admm_plan_s admm_plan = { .maxiter = conf->maxiter, .maxitercg = conf->maxitercg, .cg_eps = conf->cg_eps, .rho = conf->rho, .num_funs = D, .do_warmstart = conf->do_warmstart, .dynamic_rho = conf->dynamic_rho, .dynamic_tau = conf->dynamic_tau, .relative_norm = conf->relative_norm, .hogwild = conf->hogwild, .ABSTOL = conf->ABSTOL, .RELTOL = conf->RELTOL, .alpha = conf->alpha, .tau = conf->tau, .tau_max = conf->tau_max, .mu = conf->mu, .fast = conf->fast, .biases = biases, }; struct admm_op a_ops[D ?:1]; struct iter_op_p_s a_prox_ops[D ?:1]; for (unsigned int i = 0; i < D; i++) { a_ops[i].forward = OPERATOR2ITOP(ops[i]->forward), a_ops[i].normal = OPERATOR2ITOP(ops[i]->normal); a_ops[i].adjoint = OPERATOR2ITOP(ops[i]->adjoint); a_prox_ops[i] = OPERATOR_P2ITOP(prox_ops[i]); } admm_plan.ops = a_ops; admm_plan.prox_ops = a_prox_ops; admm_plan.xupdate = OPERATOR_P2ITOP(xupdate_op); long z_dims[D ?: 1]; for (unsigned int i = 0; i < D; i++) z_dims[i] = 2 * md_calc_size(linop_codomain(ops[i])->N, linop_codomain(ops[i])->dims); if (NULL != image_adj) { float eps = md_norm(1, MD_DIMS(size), image_adj); if (checkeps(eps)) goto cleanup; } admm(&admm_plan, admm_plan.num_funs, z_dims, size, (float*)image, image_adj, select_vecops(image), OPERATOR2ITOP(normaleq_op), monitor); cleanup: ; } void iter2_pocs(iter_conf* _conf, const struct operator_s* normaleq_op, unsigned int D, const struct operator_p_s* prox_ops[D], const struct linop_s* ops[D], const float* biases[D], const struct operator_p_s* xupdate_op, long size, float* image, const float* image_adj, struct iter_monitor_s* monitor) { auto conf = CAST_DOWN(iter_pocs_conf, _conf); assert(NULL == normaleq_op); assert(NULL == ops); assert(NULL == biases); assert(NULL == image_adj); UNUSED(xupdate_op); UNUSED(image_adj); struct iter_op_p_s proj_ops[D]; for (unsigned int i = 0; i < D; i++) proj_ops[i] = OPERATOR_P2ITOP(prox_ops[i]); pocs(conf->maxiter, D, proj_ops, select_vecops(image), size, image, monitor); }
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
void iwt2(unsigned int N, unsigned int flags, const long shifts[N], const long odims[N], const long ostr[N], complex float* out, const long idims[N], const long istr[N], const complex float* in, const long minsize[N], const long flen, const float filter[2][2][flen]) { assert(wavelet_check_dims(N, flags, odims, minsize)); if (0 == flags) { // note: recursion does *not* end here assert(md_check_compat(N, 0u, odims, idims)); md_copy2(N, idims, ostr, out, istr, in, CFL_SIZE); return; } // check input dimensions long idims2[N]; wavelet_coeffs2(N, flags, idims2, odims, minsize, flen); assert(md_check_compat(N, 0u, idims2, idims)); long wdims2[2 * N]; wavelet_dims(N, flags, wdims2, odims, flen); // only consider transform dims... long dims1[N]; md_select_dims(N, flags, dims1, odims); long wdims[2 * N]; wavelet_dims(N, flags, wdims, dims1, flen); long level_coeffs = md_calc_size(2 * N, wdims); // ... which get embedded in dimension b unsigned int b = ffs(flags) - 1; long istr2[2 * N]; md_calc_strides(2 * N, istr2, wdims, istr[b]); // merge with original strides for (unsigned int i = 0; i < N; i++) if (!MD_IS_SET(flags, i)) istr2[i] = istr[i]; assert(idims[b] >= level_coeffs); long offset = (idims[b] - level_coeffs) * (istr[b] / CFL_SIZE); long bands = md_calc_size(N, wdims + N); long coeffs = md_calc_size(N, wdims + 0); // subtract coefficients in high band idims2[b] -= (bands - 1) * coeffs; assert(idims2[b] > 0); debug_printf(DP_DEBUG4, "ifwt2: flags:%d lcoeffs:%ld coeffs:%ld (space:%ld) bands:%ld str:%ld off:%ld\n", flags, level_coeffs, coeffs, idims2[b], bands, istr[b], offset / ostr[b]); // fix me we need temp storage complex float* tmp = md_alloc_sameplace(2 * N, wdims2, CFL_SIZE, out); long tstr[2 * N]; md_calc_strides(2 * N, tstr, wdims2, CFL_SIZE); md_copy2(2 * N, wdims2, tstr, tmp, istr2, in + offset, CFL_SIZE); long shifts0[N]; for (unsigned int i = 0; i < N; i++) shifts0[i] = 0; unsigned int flags2 = wavelet_filter_flags(N, flags, wdims, minsize); assert((0 == offset) == (0u == flags2)); if (0u != flags2) { long idims3[N]; wavelet_coeffs2(N, flags2, idims3, wdims2, minsize, flen); long istr3[N]; embed(N, flags, istr3, idims3, istr); iwt2(N, flags2, shifts0, wdims2, tstr, tmp, idims3, istr3, in, minsize, flen, filter); } iwtN(N, flags, shifts, odims, ostr, out, tstr, tmp, flen, filter); md_free(tmp); }