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

Data Structures

struct  KSDIFF_CONTROL_DESIGN
 
struct  KSDIFF_CONTROL
 

Macros

#define KSDIFF_MAX_SCHEME_LENGTH   512
 
#define KSDIFF_MAXBVALS   10
 
#define KSDIFF_INIT_SCHEME   {{0,0,0}}
 
#define KSDIFF_INIT_CONTROL_DESIGN   {1, 0, KSDIFF_LOGICAL, KSDIFF_CUBOID, KS_MAT3x3_IDENTITY, 0, {0}, {0}}
 
#define KSDIFF_INIT_CONTROL   {1, 0, 0, 0, {0}, {0}, KSDIFF_INIT_SCHEME, 0.0, {0}, {0}}
 

Typedefs

typedef float KSDIFF_SCHEME[KSDIFF_MAX_SCHEME_LENGTH][3]
 

Enumerations

enum  ksdiff_coordinate_system { KSDIFF_LOGICAL, KSDIFF_PHYSICAL }
 
enum  ksdiff_physical_bound_type { KSDIFF_ISO, KSDIFF_CUBOID }
 

Functions

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 *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)
 

Macro Definition Documentation

◆ KSDIFF_MAX_SCHEME_LENGTH

#define KSDIFF_MAX_SCHEME_LENGTH   512

Maximum 512 diffusion directions

◆ KSDIFF_MAXBVALS

#define KSDIFF_MAXBVALS   10

10 different b-values > 0

◆ KSDIFF_INIT_SCHEME

#define KSDIFF_INIT_SCHEME   {{0,0,0}}

◆ KSDIFF_INIT_CONTROL_DESIGN

#define KSDIFF_INIT_CONTROL_DESIGN   {1, 0, KSDIFF_LOGICAL, KSDIFF_CUBOID, KS_MAT3x3_IDENTITY, 0, {0}, {0}}

◆ KSDIFF_INIT_CONTROL

#define KSDIFF_INIT_CONTROL   {1, 0, 0, 0, {0}, {0}, KSDIFF_INIT_SCHEME, 0.0, {0}, {0}}

Typedef Documentation

◆ KSDIFF_SCHEME

typedef float KSDIFF_SCHEME[KSDIFF_MAX_SCHEME_LENGTH][3]

2D matrix holding the b0 volumes followed by diffusion directions

Enumeration Type Documentation

◆ ksdiff_coordinate_system

Enumerator
KSDIFF_LOGICAL 
KSDIFF_PHYSICAL 
Definition: ksdiffusion.h:9
Definition: ksdiffusion.h:9
ksdiff_coordinate_system
Definition: ksdiffusion.h:9

◆ ksdiff_physical_bound_type

Enumerator
KSDIFF_ISO 
KSDIFF_CUBOID 
ksdiff_physical_bound_type
Definition: ksdiffusion.h:11
Definition: ksdiffusion.h:11
Definition: ksdiffusion.h:11

Function Documentation

◆ 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