3 #include "controller.h"
5 #include <odindata/linalg.h>
8 STD_string grappa_postlabel(
recoDim dim) {
9 return STD_string(
"grappaweights_")+recoDimLabel[dim];
15 ivector next_neighbours_offset(
unsigned int reductionFactor,
int numof_neighb,
int ired) {
16 Log<Reco> odinlog(
"",
"next_neighbours_offset");
20 int negfirst=(ired<int(reductionFactor/2));
22 for(
int i=0; i<numof_neighb; i++) {
24 if((i+negfirst)%2) result[i]=-ired-1-i2*reductionFactor;
25 else result[i]=reductionFactor-ired-1+i2*reductionFactor;
28 ODINLOG(odinlog,normalDebug) <<
"result[" << reductionFactor <<
"/" << ired <<
"]" << result << STD_endl;
35 bool measured_line(
const ivector& indexvec,
int index) {
36 for(
unsigned int i=0; i<indexvec.size(); i++) {
37 if(indexvec[i]==index)
return true;
45 coord.
set_mode(RecoIndex::separate, orthoDim);
46 coord.
index[orthoDim]=iortho;
53 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex,
class Ignore>
57 reduction_factor.set_description(
"Reduction factor");
58 append_arg(reduction_factor,
"reduction_factor");
61 neighbours_read.set_cmdline_option(
"gr").set_description(
"Number of neigbours in read direction used for GRAPPA interpolation");
62 append_arg(neighbours_read,
"neighbours_read");
65 neighbours_phase.set_cmdline_option(
"gp").set_description(
"Number of neigbouring measured k-space lines used for GRAPPA interpolation");
66 append_arg(neighbours_phase,
"neighbours_phase");
69 svd_trunc.set_cmdline_option(
"gs").set_description(
"Truncation value of SVD (i.e. regularization) when calculating GRAPPA weights");
70 append_arg(svd_trunc,
"svd_trunc");
73 discard_level.set_cmdline_option(
"gd").set_description(
"Fraction of k-psace points to discard in auto-calibration lines because of high residuals");
74 append_arg(discard_level,
"discard_level");
81 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex,
class Ignore>
86 Ignore::modify(RecoIndex::ignore, coordcopy);
89 if(!calc_weights(rdweights.data(
Rank<5>()), coordcopy, rd.
data(
Rank<4>())))
return false;
91 controller.
post_data(grappa_postlabel(interpolDim), rdweights);
92 ODINLOG(odinlog,normalDebug) <<
"Posted rdweights=" << rdweights.coord().print() << STD_endl;
94 return execute_next_step(rd,controller);
100 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex,
class Ignore>
103 if(context.mode==RecoQueryContext::prep) {
106 Ignore::modify(RecoIndex::ignore, coordcopy);
107 if(!measlines.init(coordcopy, context.
controller))
return false;
115 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex,
class Ignore>
117 Log<Reco> odinlog(c_label(),
"calc_weights");
119 Range all=Range::all();
121 ODINLOG(odinlog,normalDebug) <<
"neighbours_read/neighbours_phase=" << neighbours_read <<
"/" << neighbours_phase << STD_endl;
123 TinyVector<int,4> inshape=trainingdata.shape();
124 int nChannels=inshape(0);
125 int sizeOrtho=inshape(1+orthoIndex);
126 int sizeInterpol=inshape(1+interpolIndex);
127 int sizeRead=inshape(3);
128 ODINLOG(odinlog,normalDebug) <<
"nChannels/sizeOrtho/sizeInterpol/sizeRead/reduction_factor=" << nChannels <<
"/" << sizeOrtho <<
"/" << sizeInterpol <<
"/" << sizeRead <<
"/" << reduction_factor << STD_endl;
131 TinyVector<int,3> shape3d(inshape(1),inshape(2),inshape(3));
134 TinyVector<int,3> netshape(nChannels, neighbours_phase, neighbours_read);
136 int ncols=product(netshape);
139 weights.resize(nChannels, reduction_factor-1, nChannels, neighbours_phase, neighbours_read);
140 weights=STD_complex(0.0);
142 for(
int ired=0; ired<(reduction_factor-1); ired++) {
149 for(
int iortho=0; iortho<sizeOrtho; iortho++) {
152 set_separate_index(aclcoord, orthoDim, iortho);
154 ivector aclindices=acl_lines(aclcoord, neighbours_phase, ired);
155 ODINLOG(odinlog,normalDebug) <<
"aclindices(" << ired <<
", " << aclcoord.print() <<
")=" << aclindices << STD_endl;
157 for(
int iacl=0; iacl<int(aclindices.size()); iacl++) {
158 TinyVector<int,2> aclindex;
159 aclindex(orthoIndex)=iortho;
160 aclindex(interpolIndex)= aclindices[iacl];
161 acl_mask(all, aclindex(0), aclindex(1), Range( neighbours_read/2, sizeRead-1-neighbours_read/2 ))=1;
165 TinyVector<int,3> acl_signal_shape(shape3d);
168 ivector neighboffset=next_neighbours_offset(reduction_factor, neighbours_phase, ired);
169 ODINLOG(odinlog,normalDebug) <<
"neighboffset(" << ired <<
")=" << neighboffset.
printbody() << STD_endl;
171 for(
int ichan_dst=0; ichan_dst<nChannels; ichan_dst++) {
173 int nrows=sum(acl_mask(ichan_dst,all,all,all));
174 ODINLOG(odinlog,normalDebug) <<
"ncols/nrows=" << ncols <<
"/" << nrows << STD_endl;
176 ODINLOG(odinlog,errorLog) <<
"Not enough auto-calibration data for " << netshape <<
" interpolation net" << STD_endl;
182 Array<TinyVector<int,3>,1> maskindex(nrows);
184 for(
int i=0; i<product(acl_signal_shape); i++) {
185 TinyVector<int,3> rowindex=index2extent(acl_signal_shape, i);
186 TinyVector<int,4> aclindex(ichan_dst, rowindex(0), rowindex(1), rowindex(2));
187 if(acl_mask(aclindex)) {
188 maskindex(irow)=rowindex;
189 STD_complex aclval=trainingdata(aclindex);
190 if(cabs(aclval)==0.0) {
191 ODINLOG(odinlog,warningLog) <<
"Zero acl at " << aclindex << STD_endl;
193 acl_signal_vec(irow)=aclval;
200 for(
int irow=0; irow<nrows; irow++) {
201 TinyVector<int,3> aclindex=maskindex(irow);
203 for(
int icol=0; icol<ncols; icol++) {
204 TinyVector<int,3> windex=index2extent(netshape,icol);
206 int ichan_src=windex(0);
207 int ipoloffset=neighboffset[windex(1)];
208 int readoffset=windex(2)-neighbours_read/2;
210 TinyVector<int,4> trainingindex;
211 trainingindex(0)=ichan_src;
212 trainingindex(1)=aclindex(0);
213 trainingindex(2)=aclindex(1);
214 trainingindex(3)=aclindex(2)+readoffset;
216 trainingindex(1+interpolIndex)+=ipoloffset;
218 STD_complex trainingval=trainingdata(trainingindex);
219 if(cabs(trainingval)==0.0) {
220 ODINLOG(odinlog,warningLog) <<
"Zero trainingdata at " << trainingindex << STD_endl;
223 Matrix(irow,icol)=trainingval;
228 weights_net_vec=
solve_linear(Matrix, acl_signal_vec, svd_trunc);
232 if(discard_level>0.0) {
234 int ndiscard=int(discard_level*nrows+0.5);
235 if(ncols>(nrows-ndiscard)) {
236 ODINLOG(odinlog,warningLog) <<
"Limiting ndiscard to " << ndiscard <<
" for sufficient auto-calibration data" << STD_endl;
237 ndiscard=nrows-ncols;
239 for(
int i=0; i<ndiscard; i++) {
240 int irow_max=maxIndex(residuals)(0);
241 acl_signal_vec(irow_max)=STD_complex(0.0);
242 Matrix(irow_max,all)=STD_complex(0.0);
243 residuals(irow_max)=0.0;
247 weights_net_vec=
solve_linear(Matrix, acl_signal_vec, svd_trunc);
250 for(
int icol=0; icol<ncols; icol++) {
251 TinyVector<int,3> windex=index2extent(netshape,icol);
252 weights(ichan_dst, ired, windex(0), windex(1), windex(2))=weights_net_vec(icol);
259 ODINLOG(odinlog,normalDebug) <<
"cabs(sum(weights" << trainingcoord.
print() <<
"))=" << cabs(sum(weights)) << STD_endl;
268 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex,
class Ignore>
270 Log<Reco> odinlog(c_label(),
"acl_lines");
272 ivector neighboffset=next_neighbours_offset(reduction_factor, numof_neighb, ired);
273 ODINLOG(odinlog,normalDebug) <<
"neighboffset=" << neighboffset.
printbody() << STD_endl;
275 ivector indexvec=measlines.get_indices(coord);
276 ODINLOG(odinlog,normalDebug) <<
"indexvec(" << coord.
print() <<
")=" << indexvec.
printbody() << STD_endl;
278 STD_list<int> indexlist;
279 for(
unsigned int i=0; i<indexvec.size(); i++) {
280 int iline=indexvec[i];
282 for(
int ineighb=0; ineighb<numof_neighb; ineighb++) {
283 int neighbindex=iline+neighboffset[ineighb];
284 if(!measured_line( indexvec, neighbindex)) acl=
false;
286 if(acl) indexlist.push_back(iline);
299 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex>
303 reduction_factor.set_description(
"Reduction factor");
304 append_arg(reduction_factor,
"reduction_factor");
307 keep_shape.set_description(
"Do not correct shape of interpolated k-space according to image space size");
308 append_arg(keep_shape,
"keep_shape");
313 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex>
318 ODINLOG(odinlog,errorLog) <<
"GRAPPA weights not available" << STD_endl;
322 ODINLOG(odinlog,normalDebug) <<
"reduction_factor=" << reduction_factor << STD_endl;
325 if(!correct_shape(rd, controller))
return false;
328 ODINLOG(odinlog,normalDebug) <<
"Requesting weights for " << rd.
coord().
print() << STD_endl;
330 if(!controller.
inquire_data(*
this, grappa_postlabel(interpolDim), rdweights))
return false;
331 ODINLOG(odinlog,normalDebug) <<
"Retrieved weights with " << rdweights.coord().print() << STD_endl;
334 ODINLOG(odinlog,normalDebug) <<
"cabs(sum(weights(" << rdweights.coord().print() <<
")))=" << cabs(sum(weights)) << STD_endl;
338 TinyVector<int,4> kspaceshape=kspace.shape();
339 int nChannels=kspaceshape(0);
340 int sizeOrtho=kspaceshape(1+orthoIndex);
341 int sizeInterpol=kspaceshape(1+interpolIndex);
342 int sizeRead=kspaceshape(3);
343 ODINLOG(odinlog,normalDebug) <<
"nChannels/sizeOrtho/sizeInterpol/sizeRead/reduction_factor=" << nChannels <<
"/" << sizeOrtho <<
"/" << sizeInterpol <<
"/" << sizeRead <<
"/" << reduction_factor << STD_endl;
346 int neighbours_phase=weights.extent(3);
347 int neighbours_read=weights.extent(4);
348 ODINLOG(odinlog,normalDebug) <<
"neighbours_phase/neighbours_read=" << neighbours_phase <<
"/" << neighbours_read << STD_endl;
357 TinyVector<int,3> netshape(nChannels, neighbours_phase, neighbours_read);
361 kspace_interpol=STD_complex(0.0);
364 for(
int iortho=0; iortho<sizeOrtho; iortho++) {
368 set_separate_index(meascoord, orthoDim, iortho);
370 ivector indexvec=measlines.get_indices(meascoord);
371 ODINLOG(odinlog,normalDebug) <<
"indexvec(" << meascoord.print() <<
")=" << indexvec.
printbody() << STD_endl;
373 if(indexvec.size()) {
375 for(
int ipol=0; ipol<sizeInterpol; ipol++) {
377 if(!measured_line(indexvec, ipol)) {
379 int ired=reduction_index(indexvec, sizeInterpol, ipol);
380 ODINLOG(odinlog,normalDebug) <<
"ired(" << ipol <<
")=" << ired << STD_endl;
382 if(ired>=0 && ired<(reduction_factor-1)) {
384 set_separate_index(meascoord, interpolDim, ipol);
385 interpolated_coords[meascoord]++;
386 ODINLOG(odinlog,normalDebug) <<
"Interpolating coord " << meascoord.print() << STD_endl;
388 ivector neighboffset=next_neighbours_offset(reduction_factor, neighbours_phase, ired);
389 ODINLOG(odinlog,normalDebug) <<
"neighboffset" << neighboffset << STD_endl;
391 for(
int iread=neighbours_read/2; iread<(sizeRead-neighbours_read/2); iread++) {
392 for(
int ichan=0; ichan<nChannels; ichan++) {
394 TinyVector<int,4> kspaceindex;
395 kspaceindex(0)=ichan;
396 kspaceindex(1+orthoIndex)=iortho;
397 kspaceindex(1+interpolIndex)=ipol;
398 kspaceindex(3)=iread;
400 STD_complex interpolval(0.0);
403 for(
int i=0; i<product(netshape); i++) {
404 TinyVector<int,3> netindex=index2extent(netshape,i);
405 int jchan=netindex(0);
406 int jphase=netindex(1);
407 int jread=netindex(2);
409 int offset_ipol=neighboffset[jphase];
410 int offset_read=jread-neighbours_read/2;
412 int src_ipol =ipol+offset_ipol;
413 int src_iread =iread+offset_read;
415 if(src_ipol>=0 && src_ipol<sizeInterpol && src_iread>=0 && src_iread<sizeRead) {
417 TinyVector<int,4> srcindex;
419 srcindex(1+orthoIndex)=iortho;
420 srcindex(1+interpolIndex)=src_ipol;
421 srcindex(3)=src_iread;
423 STD_complex srcval=kspace(srcindex);
430 interpolval += srcval * weights(ichan,ired,jchan,jphase,jread);
434 kspace_interpol(kspaceindex)=interpolval;
443 kspace=kspace+kspace_interpol;
447 return execute_next_step(rd,controller);
452 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex>
454 Log<Reco> odinlog(c_label(),
"correct_shape");
456 Range all=Range::all();
459 TinyVector<int,4> inshape=inkspace.shape();
461 int nlines_dst=controller.
image_size()(interpolIndex);
462 int nlines_src=inshape(1+interpolIndex);
463 if(nlines_dst==nlines_src)
return true;
465 if(nlines_dst<nlines_src) nlines_dst=nlines_src;
466 TinyVector<int,4> outshape(inshape);
467 outshape(1+interpolIndex)=nlines_dst;
469 ODINLOG(odinlog,normalDebug) <<
"inshape/outshape=" << inshape <<
"/" << outshape << STD_endl;
472 outkspace=STD_complex(0.0);
474 Range srcrange(0,nlines_src-1);
475 if(interpolDim==line) outkspace(all,all,srcrange,all)=inkspace(all,all,srcrange,all);
476 if(interpolDim==line3d) outkspace(all,srcrange,all,all)=inkspace(all,srcrange,all,all);
487 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex>
490 if(context.mode==RecoQueryContext::prep) {
499 template<recoDim
interpolDim, recoDim orthoDim,
int interpolIndex,
int orthoIndex>
501 Log<Reco> odinlog(c_label(),
"reduction_index");
503 ODINLOG(odinlog,normalDebug) <<
"reduction_factor/sizePhase/iphase=" << reduction_factor <<
"/" << sizePhase <<
"/" << iphase << STD_endl;
509 for(
int i=iphase; i<sizePhase; i++) {
510 if(measured_line(indexvec, i)) {
517 for(
int i=iphase; i>=0; i--) {
518 if(measured_line(indexvec, i)) {
524 ODINLOG(odinlog,normalDebug) <<
"posnext/negnext(" << iphase <<
")=" << posnext <<
"/" << negnext << STD_endl;
526 if(posnext<0 || negnext<0)
return -1;
void announce_data(const STD_string &label)
bool inquire_data(const RecoStep &caller, const STD_string &label, RecoData &data)
void post_data(const STD_string &label, const RecoData &data)
bool data_announced(const STD_string &label)
TinyVector< int, 3 > image_size() const
const CoordCountMap * interpolated
ComplexData< 1 > & data(Rank< 1 >) const
grappaweights, grappaweights3d, grappaweightstempl, grappaweightstempl3d: Calculate GRAPPA weights in...
grappa, grappa3d: Perform GRAPPA interpolation in dimension 'line3d'
virtual bool query(RecoQueryContext &context)
STD_string printbody() const
Data< float, 1 > solve_linear(const Data< float, 2 > &A, const Data< float, 1 > &b, float sv_truncation=0.0)
Array< T, 1 > matrix_product(const Array< T, 2 > &matrix, const Array< T, 1 > &vector)
STD_map< RecoCoord, UInt > CoordCountMap
STD_vector< T > list2vector(const STD_list< T > &src)
RecoIndex index[n_recoDims]
RecoCoord & set_mode(RecoIndex::indexMode m, recoDim d1=n_recoDims, recoDim d2=n_recoDims, recoDim d3=n_recoDims, recoDim d4=n_recoDims, recoDim d5=n_recoDims, recoDim d6=n_recoDims, recoDim d7=n_recoDims, recoDim d8=n_recoDims)
STD_string print(RecoIndex::printMode printmode=RecoIndex::brief) const
RecoController & controller