KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
ksdiffusion.cc File Reference
#include "ksdiffusion.h"

Functions

STATUS ksdiff_readtensorfile (KSDIFF_SCHEME diffscheme, int ndirs)
 
STATUS ksdiff_eval_scheme (KSDIFF_SCHEME logical_scheme, KSDIFF_SCHEME physical_scheme, int ndirs, ksdiff_coordinate_system coordinate_system, const KS_MAT3x3f rot_l2p)
 
float ksdiff_scale_vector_to_bounds (const float *vector, const float *bounds)
 
float ksdiff_vector_mag (const float *vector)
 
float ksdiff_scale_vector_to_iso_bound (const float *vector, const float bound)
 
int ksdiff_compare_power_mag_than_x (float *amp, double mag, float *max_power_amp_scale, double max_mag)
 
int ksdiff_compare_power_x_than_mag (float *amp, double mag, float *max_power_amp_scale, double max_mag)
 
STATUS ksdiff_compute_scheme_amps (KSDIFF_SCHEME diff_amp_scaling, float *max_magnitude_amp, float *RMS_amp_scale, float *max_power_amp_scale, int(*amp_cmp_f)(float *, double, float *, double), const int ndirs, const ksdiff_coordinate_system coordinate_system, const ksdiff_physical_bound_type physical_bound_type, const KS_MAT3x3f rot_l2p)
 
float ksdiff_getmaxb (const float *bvalues, int n)
 
STATUS ksdiff_eval_design (KSDIFF_CONTROL *diff_control, const KSDIFF_CONTROL_DESIGN *design)
 
s64 ksdiff_schemeloop (const KSDIFF_CONTROL *diff_control, const KSSCAN_LOOP_CONTROL *orig_loop_control, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
void ksdiff_plotloop (const KSDIFF_CONTROL *diff_control, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const SCAN_INFO *scan_info)
 

Function Documentation

◆ ksdiff_readtensorfile()

STATUS ksdiff_readtensorfile ( KSDIFF_SCHEME  diffscheme,
int  ndirs 
)
5  {
6  int i;
7  FILE *fp;
8  char tmpstr[1000];
9  int lineskip = TRUE;
10  char matchstr[10];
11  int matchlen;
12 
13 #ifdef PSD_HW
14  const char *tensorfile = "/usr/g/research/tensor.dat";
15  const char *tensorfile2 = "/usr/g/bin/tensor.dat";
16  const char *tensorfile3 = "/opt/gehc/mr_psd_dist/root/etc/tensor.dat"; /* MR30+ */
17 #else
18  const char *tensorfile = "./tensor.dat";
19  const char *tensorfile2 = "../ksmodules/tensor.dat";
20  const char *tensorfile3 = "~/tensor.dat";
21 #endif
22 
23  if (ndirs < 1 || ndirs > 150) {
24  return KS_THROW("# diff. directions must be in range [1,150]");
25  }
26 
27  /* try first 'tensorfile' */
28  fp = fopen(tensorfile, "r" );
29  if (fp == NULL) {
30  /* then try 'tensorfile2' */
31  fp = fopen(tensorfile2, "r" );
32  if (fp == NULL) {
33  /* then try 'tensorfile3' */
34  fp = fopen(tensorfile3, "r" );
35  if (fp == NULL) {
36  return KS_THROW("Could not open file: %s or %s or %s", tensorfile, tensorfile2, tensorfile3);
37  }
38  }
39  }
40 
41  /* what to line content look for in the file */
42  sprintf(matchstr, "%d", ndirs);
43  matchlen = strlen(matchstr);
44 
45  while (lineskip) {
46  fgets(tmpstr, 1000, fp);
47  lineskip = strncmp(matchstr, tmpstr, matchlen);
48  }
49 
50  for (i = 0; i < ndirs; i++) {
51  if (fgets(tmpstr, 1000, fp) == NULL) {
52  KS_THROW("Error reading file: %s for #dirs = %d, direction %d", tensorfile, ndirs, i);
53  }
54  sscanf(tmpstr, "%f %f %f", &diffscheme[i][XGRAD], &diffscheme[i][YGRAD], &diffscheme[i][ZGRAD]);
55  }
56 
57  fclose(fp);
58 
59  return SUCCESS;
60 
61 } /* ksdiff_readtensorfile() */
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksdiff_eval_scheme()

STATUS ksdiff_eval_scheme ( KSDIFF_SCHEME  logical_scheme,
KSDIFF_SCHEME  physical_scheme,
int  ndirs,
ksdiff_coordinate_system  coordinate_system,
const KS_MAT3x3f  rot_l2p 
)
76  {
77  int i;
78 
79  if (ndirs == 0) {
80  return SUCCESS;
81  }
82 
83  if (ndirs > KSDIFF_MAX_SCHEME_LENGTH && ndirs < 0) {
84  return KS_THROW("Requested ndirs (%d) must be in the interval [0, %d]", ndirs, KSDIFF_MAX_SCHEME_LENGTH);
85  }
86 
87  float (*diffscheme)[3] = coordinate_system == KSDIFF_LOGICAL ?
88  logical_scheme : physical_scheme;
89 
90  /* clear table */
91  for (i = 0; i < KSDIFF_MAX_SCHEME_LENGTH; i++) {
92  diffscheme[i][XGRAD] = diffscheme[i][YGRAD] = diffscheme[i][ZGRAD] = 0.0;
93  }
94 
95  /* set diffusion directions (b0 volumes are already zero, since we cleared the sequence) */
96  switch (ndirs) {
97  case 1: {
98  diffscheme[0][XGRAD] = 0;
99  diffscheme[0][YGRAD] = 0;
100  diffscheme[0][ZGRAD] = 1; /* Z only */
101  break;
102  }
103  case 2:
104  case 3: {
105 
106  for (i = 0; i < 3; i++) {
107  diffscheme[i][i] = 1;
108  }
109  break;
110  }
111  case 4: {
112 
113  diffscheme[0][XGRAD] = 1;
114  diffscheme[0][YGRAD] = 1;
115  diffscheme[0][ZGRAD] = 1;
116 
117  diffscheme[1][XGRAD] = -1;
118  diffscheme[1][YGRAD] = 1;
119  diffscheme[1][ZGRAD] = 1;
120 
121  diffscheme[2][XGRAD] = 1;
122  diffscheme[2][YGRAD] = -1;
123  diffscheme[2][ZGRAD] = 1;
124 
125  diffscheme[3][XGRAD] = -1;
126  diffscheme[3][YGRAD] = -1;
127  diffscheme[3][ZGRAD] = 1;
128 
129  break;
130  }
131  case 5:
132  case 6: {
133 
134  diffscheme[0][XGRAD] = 1;
135  diffscheme[0][YGRAD] = 1;
136  diffscheme[0][ZGRAD] = 0;
137 
138  diffscheme[1][XGRAD] = -1;
139  diffscheme[1][YGRAD] = 1;
140  diffscheme[1][ZGRAD] = 0;
141 
142  diffscheme[2][XGRAD] = 1;
143  diffscheme[2][YGRAD] = 0;
144  diffscheme[2][ZGRAD] = 1;
145 
146  diffscheme[3][XGRAD] = -1;
147  diffscheme[3][YGRAD] = 0;
148  diffscheme[3][ZGRAD] = 1;
149 
150  diffscheme[4][XGRAD] = 0;
151  diffscheme[4][YGRAD] = 1;
152  diffscheme[4][ZGRAD] = 1;
153 
154  diffscheme[5][XGRAD] = 0;
155  diffscheme[5][YGRAD] = -1;
156  diffscheme[5][ZGRAD] = 1;
157 
158  break;
159  }
160  default: {
161 
162  STATUS s = ksdiff_readtensorfile(diffscheme, ndirs);
163  KS_RAISE(s);
164  }
165  }
166 
167  for (i = 0; i < ndirs; i++) {
168  if (coordinate_system == KSDIFF_LOGICAL) {
169  ks_mat3f_apply(physical_scheme[i], rot_l2p, logical_scheme[i]);
170  } else {
171  ks_mat3f_invapply(logical_scheme[i], rot_l2p, physical_scheme[i]);
172  }
173  }
174 
175  return SUCCESS;
176 
177 } /* ksdiff_eval_scheme() */
#define KSDIFF_MAX_SCHEME_LENGTH
Definition: ksdiffusion.h:6
STATUS ksdiff_readtensorfile(KSDIFF_SCHEME diffscheme, int ndirs)
Definition: ksdiffusion.cc:5
void ks_mat3f_invapply(float *w, const KS_MAT3x3f R, const float *v)
Same as ks_mat3f_apply but use transpose of Rotation (R)
Definition: KSFoundation_common.c:4001
void ks_mat3f_apply(float *w, const KS_MAT3x3f R, const float *v)
Rotate a vector with a 3x3 matrix
Definition: KSFoundation_common.c:3987
#define KS_RAISE(status)
Definition: KSFoundation.h:190
Definition: ksdiffusion.h:9
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksdiff_scale_vector_to_bounds()

float ksdiff_scale_vector_to_bounds ( const float *  vector,
const float *  bounds 
)
184  {
185  float scale = 1.0f/0.0f; /* +Inf */
186  int i;
187  for (i=0; i<3; i++) {
188  /* TODO: protect against div by zero */
189  const float ratio = fabs(bounds[i]) / fabs(vector[i]);
190  if (scale > ratio) {
191  scale = ratio;
192  }
193  }
194  return scale;
195 
196 } /* ksdiff_scale_vector_to_bounds() */
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)

◆ ksdiff_vector_mag()

float ksdiff_vector_mag ( const float *  vector)
202  {
203 
204  double acc = 0.0;
205  int i;
206  for (i=0; i<3; i++) {
207  acc += vector[i] * vector[i];
208  }
209  return sqrt(acc);
210 
211 } /* ksdiff_vector_mag() */

◆ ksdiff_scale_vector_to_iso_bound()

float ksdiff_scale_vector_to_iso_bound ( const float *  vector,
const float  bound 
)
218  {
219 
220  /* TODO: protect against div by zero */
221  return fabs(bound) / ksdiff_vector_mag(vector);
222 
223 } /* ksdiff_scale_vector_to_iso_bound() */
float ksdiff_vector_mag(const float *vector)
Definition: ksdiffusion.cc:202

◆ ksdiff_compare_power_mag_than_x()

int ksdiff_compare_power_mag_than_x ( float *  amp,
double  mag,
float *  max_power_amp_scale,
double  max_mag 
)
231  {
232 
233  if (mag >= max_mag &&
234  amp[XGRAD] > max_power_amp_scale[XGRAD]) {
235  return 1;
236  }
237  return 0;
238 
239 } /* ksdiff_compare_power_mag_than_x() */

◆ ksdiff_compare_power_x_than_mag()

int ksdiff_compare_power_x_than_mag ( float *  amp,
double  mag,
float *  max_power_amp_scale,
double  max_mag 
)
247  {
248 
249  if (amp[XGRAD] >= max_power_amp_scale[XGRAD] &&
250  mag > max_mag) {
251  return 1;
252  }
253  return 0;
254 
255 } /* ksdiff_compare_power_x_than_mag() */

◆ ksdiff_compute_scheme_amps()

STATUS ksdiff_compute_scheme_amps ( KSDIFF_SCHEME  diff_amp_scaling,
float *  max_magnitude_amp,
float *  RMS_amp_scale,
float *  max_power_amp_scale,
int(*)(float *, double, float *, double)  amp_cmp_f,
const int  ndirs,
const ksdiff_coordinate_system  coordinate_system,
const ksdiff_physical_bound_type  physical_bound_type,
const KS_MAT3x3f  rot_l2p 
)
268  {
269  STATUS status;
270  int i, b;
271 
272  for (b = 0; b < 3; b++) {
273  RMS_amp_scale[b] = 0;
274  max_power_amp_scale[b] = 0;
275  }
276 
277  if (ndirs < 1) {
278  return SUCCESS;
279  }
280 
281  /* Generate the diffusion scheme */
282  /* TODO: dynamic allocation maybe? */
283  KSDIFF_SCHEME logical_scheme;
284  KSDIFF_SCHEME physical_scheme;
285  status = ksdiff_eval_scheme(logical_scheme,
286  physical_scheme,
287  ndirs,
288  coordinate_system,
289  rot_l2p);
290  KS_RAISE(status);
291 
292  /* TODO: should we check also slewrate? */
293  const float logical_amp_bounds[3] = {loggrd.tx, loggrd.ty, loggrd.tz};
294  const float physical_amp_bounds[3] = {phygrd.xfs, phygrd.yfs, phygrd.zfs};
295  const float physical_amp_iso_bound = FMin(3, phygrd.xfs, phygrd.yfs, phygrd.zfs);
296 
297  /* Note that both scale and global_scale turn diffusion directions, whatever
298  their units, into gradient amplitudes [G/cm] */
299  float scale;
300  float global_scale = 1.0f/0.0f; /* +Inf */
301  for (i = 0; i < ndirs; i++) {
302 
303  /* Check logical constraints */
304  scale = ksdiff_scale_vector_to_bounds(logical_scheme[i], logical_amp_bounds);
305  if (scale < global_scale) { global_scale = scale; }
306 
307  /* Check physical constraints */
308  if (physical_bound_type == KSDIFF_ISO) {
309  scale = ksdiff_scale_vector_to_iso_bound(physical_scheme[i], physical_amp_iso_bound);
310  } else {
311  scale = ksdiff_scale_vector_to_bounds(physical_scheme[i], physical_amp_bounds);
312  }
313  if (scale < global_scale) { global_scale = scale; }
314  }
315 
316  /*
317  now that we have the maximum feasible scaling factor we can compute the
318  amp scaling factors for each direction and the absolute maximum
319  magnitude of the gradient amplitudes over all directions.
320  */
321  *max_magnitude_amp = 0; /* [G/cm] */
322 
323  double max_power_mag = 0; /* [G/cm] */
324 
325  if (!amp_cmp_f) {
326  /* Default comparator */
328  }
329 
330  for (i = 0; i < ndirs; i++) {
331  double magnitude_amp = 0;
332  for (b = 0; b < 3; b++) {
333 
334  const float amp = logical_scheme[i][b]*global_scale; /* [G/cm] */
335  magnitude_amp += amp * amp;
336 
337  /* belongs in [-1, 1] */
338  diff_amp_scaling[i][b] = amp / logical_amp_bounds[b];
339 
340  /* Accumulate RMS amp */
341  RMS_amp_scale[b] += diff_amp_scaling[i][b] * diff_amp_scaling[i][b];
342  }
343  magnitude_amp = sqrt(magnitude_amp); /* [G/cm] */
344  if (magnitude_amp > *max_magnitude_amp) {
345  *max_magnitude_amp = magnitude_amp;
346  }
347 
348  /* Update maximum power amp */
349  if (amp_cmp_f(diff_amp_scaling[i], magnitude_amp, max_power_amp_scale, max_power_mag)) {
350  for (b = 0; b < 3; b++) {
351  max_power_amp_scale[b] = diff_amp_scaling[i][b];
352  max_power_mag = magnitude_amp;
353  }
354  }
355  }
356 
357  /* Finalize RMS amp */
358  for (b = 0; b < 3; b++) {
359  RMS_amp_scale[b] = sqrt(RMS_amp_scale[b]/ndirs);
360  }
361 
362  return SUCCESS;
363 
364 } /* ksdiff_compute_scheme_amps() */
float ksdiff_scale_vector_to_bounds(const float *vector, const float *bounds)
Definition: ksdiffusion.cc:183
float KSDIFF_SCHEME[KSDIFF_MAX_SCHEME_LENGTH][3]
Definition: ksdiffusion.h:13
Definition: ksdiffusion.h:11
PHYS_GRAD phygrd
float ksdiff_scale_vector_to_iso_bound(const float *vector, const float bound)
Definition: ksdiffusion.cc:217
LOG_GRAD loggrd
#define KS_RAISE(status)
Definition: KSFoundation.h:190
int ksdiff_compare_power_x_than_mag(float *amp, double mag, float *max_power_amp_scale, double max_mag)
Definition: ksdiffusion.cc:244
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)
STATUS ksdiff_eval_scheme(KSDIFF_SCHEME logical_scheme, KSDIFF_SCHEME physical_scheme, int ndirs, ksdiff_coordinate_system coordinate_system, const KS_MAT3x3f rot_l2p)
Definition: ksdiffusion.cc:72

◆ ksdiff_getmaxb()

float ksdiff_getmaxb ( const float *  bvalues,
int  n 
)
369  {
370 
371  int i;
372  float maxb = 0.0;
373  for (i = 0; i < n; i++) {
374  if (bvalues[i] > maxb) {
375  maxb = fabs(bvalues[i]);
376  }
377  }
378  return maxb;
379 
380 } /* ksdiff_getmaxb() */

◆ ksdiff_eval_design()

STATUS ksdiff_eval_design ( KSDIFF_CONTROL diff_control,
const KSDIFF_CONTROL_DESIGN design 
)

Generate a diffusion control from its design

This function computes the scaling factors needed for the desired diffusion scheme to be executed taking into accout the limits of the gradient system according to design->physical_bound_type. The actual shape and timing of the diffusion gradients are not needed to be known, in fact, this function must be called before setting up the module that includes the diffusion gradients. In particular diff_control->bvalue and diff_control->max_magnitude_amp are to be used as inputs to design the diffusion gradients (see below for an example). Additionally, diff_control->RMS_amp_scale and diff_control->max_power_amp_scale are to be used for setting the diffusion gradients scaling factors for gradient heating calculations for average and maximum power respectively.

NOTE* that it is assumed that the diffusion gradients are generated with a maximum amplitude equal for each board equal to that board's maximum amplitude, possibly scaled down by a common factor. Each board's mximum amplitude is stored in tx, ty and tz from loggrd. In particular, one waveform (trapezoid or wave) per board is needed since those values are not necessarily equal. Specifically, the maximum amplitude of the diffusion gradients on the X logical board should be equal to alpha*loggrd.tx where alpha is a scaling factor (0 < alpha <= 1). Similarly, the maximum amplitude of the diffusion gradients on the Y and Z logical boards should be equal to alpha*loggrd.ty and alpha*loggrd.tz respectively.

For instance, in the case of standard diffusion gradients, the maximum amplitude is achieved during the plateau of the trapezoids. In order to design the shape of those trapezoids, a ramp time must be chosen first. If in doubt ks_syslimits_ramptimemax(loggrd) is always feasible as it represents the time for the slowest board to reach its maximum amplitude. Then the plateau time and the time separation between the two trapezoids should be chosen so that a plateau amplitude equal to alpha*diff_control->max_magnitude_amp results in a b-value equal to diff_control->bvalue. Finally, the actual trapezoids for the X, Y and Z boards need to be generated with a plateau amplitude equal to alpha*loggrd.tx, alpha*loggrd.ty and alpha*loggrd.tz respectively.

Parameters
[out]diff_control
[in]design
Returns
STATUS
386  {
387 
388  STATUS status;
389  int i;
390 
391  /* TODO: We may want to check for Premier gradients */
392 
393  /* Copy fields */
394  diff_control->nb0 = design->nb0;
395  diff_control->ndirs = design->ndirs;
396  diff_control->numbvals = design->numbvals;
397 
398  const float maxb = ksdiff_getmaxb(design->bvalues, design->numbvals);
399  diff_control->bvalue = maxb;
400  for (i=0; i < KSDIFF_MAXBVALS; ++i) {
401  diff_control->multib_scale[i] = fabs(design->bvalues[i]) / maxb;
402  diff_control->multib_nex[i] = design->multib_nex[i];
403  }
404 
405  status = ksdiff_compute_scheme_amps(diff_control->diff_amp_scaling,
406  &diff_control->max_magnitude_amp,
407  diff_control->RMS_amp_scale,
408  diff_control->max_power_amp_scale,
409  NULL, /* Default comparator */
410  design->ndirs,
411  design->coordinate_system,
412  design->physical_bound_type,
413  design->rot_l2p);
414  KS_RAISE(status);
415 
416  return SUCCESS;
417 
418 } /* ksdiff_eval_design() */
int ndirs
Definition: ksdiffusion.h:24
float bvalue
Definition: ksdiffusion.h:46
int nb0
Definition: ksdiffusion.h:23
int ndirs
Definition: ksdiffusion.h:44
int nb0
Definition: ksdiffusion.h:43
float ksdiff_getmaxb(const float *bvalues, int n)
Definition: ksdiffusion.cc:369
float max_power_amp_scale[3]
Definition: ksdiffusion.h:52
float RMS_amp_scale[3]
Definition: ksdiffusion.h:51
int numbvals
Definition: ksdiffusion.h:28
int multib_nex[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:48
KSDIFF_SCHEME diff_amp_scaling
Definition: ksdiffusion.h:49
STATUS ksdiff_compute_scheme_amps(KSDIFF_SCHEME diff_amp_scaling, float *max_magnitude_amp, float *RMS_amp_scale, float *max_power_amp_scale, int(*amp_cmp_f)(float *, double, float *, double), const int ndirs, const ksdiff_coordinate_system coordinate_system, const ksdiff_physical_bound_type physical_bound_type, const KS_MAT3x3f rot_l2p)
Definition: ksdiffusion.cc:260
KS_MAT3x3f rot_l2p
Definition: ksdiffusion.h:27
#define KS_RAISE(status)
Definition: KSFoundation.h:190
ksdiff_physical_bound_type physical_bound_type
Definition: ksdiffusion.h:26
float bvalues[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:29
float multib_scale[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:47
float max_magnitude_amp
Definition: ksdiffusion.h:50
int multib_nex[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:30
int numbvals
Definition: ksdiffusion.h:45
ksdiff_coordinate_system coordinate_system
Definition: ksdiffusion.h:25
#define KSDIFF_MAXBVALS
Definition: ksdiffusion.h:7

◆ ksdiff_schemeloop()

s64 ksdiff_schemeloop ( const KSDIFF_CONTROL diff_control,
const KSSCAN_LOOP_CONTROL loop_control,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

Executes all loops for a diffusion scheme according to the provided loop control

The index dynamic->vol is incremented for each b0 and each diffusion volumes. This corresponds to a total number of sampled volumes equal to nb0 + numbvals*ndirs for each invocation of ksdiff_schemeloop.

Note that dynamic->vol is not reset to zero so that, if the diffusion scheme is repeated, all volumes have different index.

Parameters
[in]diff_control
[in]loop_control
[in,out]dynamic
[in]coreslice
Returns
s64 Time necessary for performing all relevant loops on the hardware
431  {
432 
433  s64 time = 0;
434 
435  KS_DYNAMIC_STATE default_dynamic = KS_INIT_DYNAMIC_STATE;
436  if (!dynamic) {
437  dynamic = &default_dynamic;
438  }
439 
440  /* make a copy of the loop control as we are going to modify some */
441  KSSCAN_LOOP_CONTROL loop_control = *orig_loop_control;
442 
443  const int numbval_indices = diff_control->nb0 + diff_control->numbvals;
444  int board;
445 
446  /* Initialize for b0s */
447  loop_control.naverages = orig_loop_control->naverages;
448  float bvalue_scale = 0;
449  int ndirs = 1;
450 
451  for (dynamic->b_idx = 0; dynamic->b_idx < numbval_indices; dynamic->b_idx++) {
452 
453  if (dynamic->b_idx >= diff_control->nb0) {
454  const int bvalue_idx = dynamic->b_idx - diff_control->nb0;
455  loop_control.naverages = diff_control->multib_nex[bvalue_idx];
456  bvalue_scale = diff_control->multib_scale[bvalue_idx];
457  ndirs = diff_control->ndirs;
458  }
459 
460  for (dynamic->diff_idx = 0; dynamic->diff_idx < ndirs; dynamic->diff_idx++) {
461  for (dynamic->pass = 0; dynamic->pass < loop_control.slicetiming.slice_plan.npasses; dynamic->pass++) {
462 
463  /* In a single pass scan we should play dummies only once */
464  const int play_dda = loop_control.slicetiming.slice_plan.npasses == 1 ?
465  (!(dynamic->vol) && !dynamic->b_idx && !dynamic->diff_idx) : 1;
466  loop_control.dda = play_dda * orig_loop_control->dda;
467 
468  /*
469  Set up the diffusion amplitudes
470 
471  Note: diff_amp assumes that the diffusion gradients are generated
472  with amplitude equal to loggrd.t*
473  */
474  for (board = 0; board < 3; board++) {
475  dynamic->diff_amp[board] = bvalue_scale > 0 ?
476  bvalue_scale*diff_control->diff_amp_scaling[dynamic->diff_idx][board] : 0.0f;
477  }
478 
479  time += ksscan_acqloop(&loop_control, dynamic, coreslice);
480 
481  loop_control.dda = 0;
482  if (loop_control.play_endofpass) {
483  time += GEReq_endofpass();
484  }
486 
487  } /* pass loop */
488 
489  /* Done with a volume */
490  dynamic->vol++;
491 
492  } /* diff_idx loop */
493  } /* b_idx loop */
494 
495  return time; /* in [us] */
496 
497 } /* ksdiff_schemeloop() */
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int ndirs
Definition: ksdiffusion.h:44
int nb0
Definition: ksdiffusion.h:43
int play_endofpass
Definition: ksscan.h:188
s64 ksscan_acqloop(const KSSCAN_LOOP_CONTROL *loop_control, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
Executes all loops for a single pass/acquisition
Definition: ksscan.cc:504
int dda
Definition: ksscan.h:185
int naverages
Definition: ksscan.h:187
int npasses
Definition: KSFoundation.h:1319
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
int multib_nex[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:48
KSDIFF_SCHEME diff_amp_scaling
Definition: ksdiffusion.h:49
Structure containing all the information to perform a standard scan loop
Definition: ksscan.h:184
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:3621
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_common.c:4286
float multib_scale[KSDIFF_MAXBVALS]
Definition: ksdiffusion.h:47
Definition: KSFoundation.h:409
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
int numbvals
Definition: ksdiffusion.h:45

◆ ksdiff_plotloop()

void ksdiff_plotloop ( const KSDIFF_CONTROL diff_control,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
const SCAN_INFO *  scan_info 
)

Executes a loop over all diffusion direction for plotting purposes

All loops other than the one over all diffusion directions are collapsed.

Parameters
[in]diff_control
[in]coreslice
[in]scan_infoOptional slice position, can be NULL
Returns
void
504  {
505 
506  KS_DYNAMIC_STATE dynamic = KS_INIT_DYNAMIC_STATE;
507 
508  SCAN_INFO default_scan_info = DEFAULT_AXIAL_SCAN_INFO;
509  if (!scan_info) {
510  scan_info = &default_scan_info;
511  }
512 
513  /* Once for b0 */
514  coreslice(scan_info, &dynamic);
515 
516  int dir, board;
517  for (dir = 0; dir < diff_control->ndirs; dir++) {
518  for (board = 0; board < 3; board++) {
519  dynamic.diff_amp[board] =
520  diff_control->diff_amp_scaling[dir][board];
521  }
522 
523  coreslice(scan_info, &dynamic);
524  }
525 
526 } /* ksdiff_plotloop() */
int ndirs
Definition: ksdiffusion.h:44
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
KSDIFF_SCHEME diff_amp_scaling
Definition: ksdiffusion.h:49
SCAN_INFO scan_info[]
#define DEFAULT_AXIAL_SCAN_INFO
Definition: GERequired.e:160