KSFoundation  [April-2021]
A platform for simpler EPIC programming on GE MR systems
GERequired.e File Reference

Macros

#define seq_name   ]_set
 
#define GEREQUIRED_E
 
#define CLINICAL_MODE   0
 
#define MAX_ENTRY_POINTS   15
 
#define MAX_TR_OVERSHOOT   200 /* 200 us round-up allowed per TR */
 
#define MAX_TR_UNDERSHOOT   16 /* 16 us round-down allowed per TR */
 
#define DEFAULT_SCAN_INFO_HEAD   0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0
 
#define DEFAULT_AXIAL_SCAN_INFO
 
#define DEFAULT_AX_SCAN_INFO_FREQ_LR   DEFAULT_AXIAL_SCAN_INFO
 
#define DEFAULT_AX_SCAN_INFO_FREQ_AP
 
#define DEFAULT_SAG_SCAN_INFO_FREQ_SI
 
#define DEFAULT_SAG_SCAN_INFO_FREQ_AP
 
#define DEFAULT_COR_SCAN_INFO_FREQ_SI
 
#define DEFAULT_COR_SCAN_INFO_FREQ_LR
 
#define KS_PSD_USE_APX   0
 

Typedefs

typedef int bool
 

Functions

 KS_SEQLENGTH (seq_name, seq_struct)
 
STATUS calcPulseParams (int p)
 
STATUS simscan (void)
 
STATUS GEReq_init_gradspecs (LOG_GRAD *loggrd, PHYS_GRAD *phygrd, float srfact)
 
STATUS GEReq_init_accelUI (int integeraccel, int maxaccel)
 
STATUS GEReq_eval_TRrange (int *slperpass, int *timetoadd_perTR, int requested_minacqs, int mintr, int maxtr, KS_SEQ_COLLECTION *seqcollection, int(*play_loop)(int, int, void **), int nargs, void **args)
 
STATUS GEReq_eval_TR (int *slperpass, int *timetoadd_perTR, int requested_minacqs, KS_SEQ_COLLECTION *seqcollection, int(*play_loop)(int, int, void **), int nargs, void **args)
 
STATUS GEReq_eval_rfscaling (KS_SEQ_COLLECTION *seqcollection)
 
STATUS GEReq_eval_checkTR_SAR_calcs (KS_SEQ_COLLECTION *seqcollection, int intended_time)
 
STATUS GEReq_eval_checkTR_SAR (KS_SEQ_COLLECTION *seqcollection, int nslices, int(*play_loop)(int, int, void **), int nargs, void **args)
 
STATUS GEReq_predownload_store_sliceplan (KS_SLICE_PLAN slice_plan)
 
STATUS GEReq_predownload_store_sliceplan3D (int slices_in_slab, int slabs)
 
STATUS GEReq_predownload_setfilter (FILTER_INFO *filt)
 
STATUS GEReq_predownload_genVRGF (const KS_READTRAP *const readtrap)
 
STATUS GEReq_predownload_genrowflip (KS_EPI *epi, int blipsign, int assetflag, int dorowflip)
 
STATUS GEReq_predownload_setrecon_writekacq (const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser)
 
STATUS GEReq_predownload_setrecon_accel (const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser, int datadestination)
 
void GEReq_predownload_setrecon_phase (const KS_PHASER *const phaser, const float readfov, const int datadestination)
 
void GEReq_predownload_setrecon_readwave (const KS_READWAVE *const readwave, const int yres, const int xres, int imsize_policy, int datadestination)
 
void GEReq_predownload_setrecon_readphase (const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser, int imsize_policy, int datadestination)
 
void GEReq_predownload_setrecon_annotations (int tsp, int readdur, int time2center, int echogap)
 
void GEReq_predownload_setrecon_annotations_readtrap (KS_READTRAP *readtrap, int echogap)
 
void GEReq_predownload_setrecon_annotations_epi (KS_EPI *epi, int echogap)
 
void GEReq_predownload_setrecon_voldata (int numvols, const KS_SLICE_PLAN slice_plan)
 
STATUS GEReq_predownload_setrecon_epi (KS_EPI *epi, int numvols2store, const KS_SLICE_PLAN slice_plan, int echogap, int blipsign, int datadestination, int multishotflag, int staticghostcal, int imsize_policy)
 
STATUS GEReq_predownload_prescan_options (RG_CAL_MODE_E rg_cal_mode)
 
STATUS GEReq_cvinit (void)
 
STATUS GEReq_cveval (void)
 
void getAPxParam (optval *min, optval *max, optdelta *delta, optfix *fix, float coverage, int algorithm)
 
int getAPxAlgorithm (optparam *optflag, int *algorithm)
 
STATUS GEReq_cvcheck (void)
 
STATUS GEReq_predownload (void)
 
void GEReq_pulsegenBegin (void)
 
void GEReq_pulsegenEnd (void)
 
int GEReq_endofpass ()
 
int GEReq_endofscan ()
 
int GEReq_endofpassandscan ()
 
void dummylinks (void)
 
void GEReq_initRSP (void)
 

Variables

RF_PULSE_INFO rfpulseInfo [RF_FREE] = { {0, 0} }
 
int avail_image_time
 
ifndef ACT_TR_EXISTS int act_tr
 
endif SCAN_INFO ks_scan_info [SLTAB_MAX] = {DEFAULT_AXIAL_SCAN_INFO}
 
KS_SLICE_PLAN ks_slice_plan = KS_INIT_SLICEPLAN
 
int ks_sarcheckdone = FALSE
 
char ks_psdname [256]
 
int ks_perform_slicetimeplot = FALSE
 
int obl_debug = 0 with {0, 1, 0, INVIS, "On(=1) to print messages for obloptimize",}
 
int obl_method = PSD_OBL_OPTIMAL with {PSD_OBL_RESTRICT, PSD_OBL_OPTIMAL, PSD_OBL_OPTIMAL, INVIS, "On(=1) to optimize the targets based on actual rotation matrices",}
 
int filter_echo1 = 0 with {, , , INVIS, "Scan filter slot number needed for prescan",}
 
int pw_passpacket = 50ms with {10ms, 1000ms, 50ms, VIS, "Duration of the passpacket sequence",}
 
int ks_rfconf = ENBL_RHO1 + ENBL_THETA + ENBL_OMEGA + ENBL_OMEGA_FREQ_XTR1
 
int ks_simscan = 1 with {0, 1, 1, VIS, "Simulate slice locations if 1 (and in simulation)",}
 
float ks_srfact = 1.0 with {0.01, 3.0, 1.0, VIS, "Slewrate factor (low value = slower gradients)",}
 
float ks_qfact = 1.0 with {0.1, 40.0, 1.0, VIS, "Quietness factor",}
 
float ks_gheatfact = 1.0 with {0.0, 1.0, 1.0, VIS, "Degree of honoring gradient heating calculations (0:ignore, 1:fully obey)"}
 
int ks_plot_filefmt = KS_PLOT_MAKEPNG with {KS_PLOT_OFF,KS_PLOT_MAKEPNG,KS_PLOT_MAKEPNG, VIS, "Plot format 0:off 1:PDF 2:SVG 3:PNG"}
 
int ks_plot_kstmp = FALSE with {FALSE,TRUE,FALSE, VIS, "0: off 1:Copy plots to mrraw/kstmp"}
 
int ks_clinicalmode = CLINICAL_MODE with {0, 1, CLINICAL_MODE, VIS, "Clinical mode: on=1 / off=0"}
 
float maxB1 [MAX_ENTRY_POINTS]
 
float maxB1Seq
 
short debugstate
 
short viewtable [513]
 
PSD_EXIT_ARG psdexitarg
 
int rspent
 
int rspdda
 
int rspbas
 
int rspvus
 
int rspgy1
 
int rspasl
 
int rspesl
 
int rspchp
 
int rspnex
 
int rspslq
 
int rspsct
 
int rsprep
 
short chopamp
 
int seqCount
 
int view
 
int excitation
 
int debug
 
const CHAR * entry_name_list [ENTRY_POINT_MAX]
 

Detailed Description

This file has several sections that should be @inline'd for a main pulse sequence written entirely in KSFoundation EPIC. See instructions for each section on where to @inline.

Macro Definition Documentation

◆ seq_name

#define seq_name   ]_set

◆ GEREQUIRED_E

#define GEREQUIRED_E

◆ CLINICAL_MODE

#define CLINICAL_MODE   0

◆ MAX_ENTRY_POINTS

#define MAX_ENTRY_POINTS   15

◆ MAX_TR_OVERSHOOT

#define MAX_TR_OVERSHOOT   200 /* 200 us round-up allowed per TR */

◆ MAX_TR_UNDERSHOOT

#define MAX_TR_UNDERSHOOT   16 /* 16 us round-down allowed per TR */

◆ DEFAULT_SCAN_INFO_HEAD

#define DEFAULT_SCAN_INFO_HEAD   0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0

◆ DEFAULT_AXIAL_SCAN_INFO

#define DEFAULT_AXIAL_SCAN_INFO
Value:
{ DEFAULT_SCAN_INFO_HEAD, {1.0, 0.0, 0.0, \
0.0, 1.0, 0.0, \
0.0, 0.0, 1.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ DEFAULT_AX_SCAN_INFO_FREQ_LR

#define DEFAULT_AX_SCAN_INFO_FREQ_LR   DEFAULT_AXIAL_SCAN_INFO

◆ DEFAULT_AX_SCAN_INFO_FREQ_AP

#define DEFAULT_AX_SCAN_INFO_FREQ_AP
Value:
{ DEFAULT_SCAN_INFO_HEAD, {0.0, 1.0, 0.0, \
-1.0, 0.0, 0.0, \
0.0, 0.0, 1.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ DEFAULT_SAG_SCAN_INFO_FREQ_SI

#define DEFAULT_SAG_SCAN_INFO_FREQ_SI
Value:
{ DEFAULT_SCAN_INFO_HEAD, {0.0, 0.0, 1.0, \
0.0, 1.0, 0.0, \
-1.0, 0.0, 0.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ DEFAULT_SAG_SCAN_INFO_FREQ_AP

#define DEFAULT_SAG_SCAN_INFO_FREQ_AP
Value:
{ DEFAULT_SCAN_INFO_HEAD, {0.0, 0.0, 1.0, \
1.0, 0.0, 0.0, \
0.0, 1.0, 0.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ DEFAULT_COR_SCAN_INFO_FREQ_SI

#define DEFAULT_COR_SCAN_INFO_FREQ_SI
Value:
{ DEFAULT_SCAN_INFO_HEAD, {0.0, 1.0, 0.0, \
0.0, 0.0, 1.0, \
1.0, 0.0, 0.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ DEFAULT_COR_SCAN_INFO_FREQ_LR

#define DEFAULT_COR_SCAN_INFO_FREQ_LR
Value:
{ DEFAULT_SCAN_INFO_HEAD, {-1.0, 0.0, 0.0, \
0.0, 0.0, 1.0, \
0.0, 1.0, 0.0}}
#define DEFAULT_SCAN_INFO_HEAD
Definition: GERequired.e:148

◆ KS_PSD_USE_APX

#define KS_PSD_USE_APX   0

Typedef Documentation

◆ bool

typedef int bool

Function Documentation

◆ KS_SEQLENGTH()

KS_SEQLENGTH ( seq_name  ,
seq_struct   
)

Creates a hardware sequence for the current sequence module

This EPIC macro is adapted from GE's EPIC macro SEQLENGTH. The seqctrl (KS_SEQ_CONTROL) struct for the current sequence module is passed in as the second argument to this function, where seqctrl.duration holds the information on the duration of the sequence module and passed on to createseq(). During scanning, ks_scan_playsequence(), which takes a KS_SEQ_CONTROL struct as input, internally calls boffset() to make a real-time hardware switch to this sequence module by passing in seqctrl.handle.offset set by KS_SEQLENGTH().

KS_SEQLENGTH() must be called in pulsegen() after the sequence (module) has been layed out using various ks_pg_*** calls. It must also be after GEReq_pulsegenBegin() and before GEReq_pulsegenEnd() and buildinstr(). The first argument to KS_SEQLENGTH() is GE's name of the pulse sequence module, which by convention usually begins with "seq***". The hardware sequence handle is then named off_seq*** and this handle is stored in seqctrl.handle.offset.

EPIC macro Parameters

  • arg 1: Name of the sequence module (only used for this function call)
  • arg 2: The KS_SEQ_CONTROL struct for the current sequence module
65  {
66 
67 var: {
68 #ifndef $[seq_name]_set
69 #define $[seq_name]_set
70 #else
71 #error KS_SEQLENGTH: Sequence name $[seq_name] (arg 1) already taken
72 #endif
73  SEQUENCE_ENTRIES off_$[seq_name];
74  WF_PULSE $[seq_name];
75 #if defined(HOST_TGT)
76  int idx_$[seq_name]; /* sequence entry index */
77 #endif
78  }
79 insert: predownload => {
80  /* dont indent the closing bracket */
81 }
82 insert: cvinit => {
83  /* dont indent the closing bracket */
84 }
85 
86 subst: {
87  {
88  if ($[seq_struct].duration > 0) {
89 
90  if ($[seq_struct].duration - $[seq_struct].ssi_time < 0) {
91 
92  ks_error("KS_SEQLENGTH (%s): (.duration - .ssi_time) is negative", $[seq_struct].description);
93 
94  } else {
95 
96  STATUS status = pulsename(&$[seq_name], "$[seq_name]");
97  if (status != SUCCESS) {
98  ks_error("KS_SEQLENGTH (%s): pulsename($[seq_name]) failed", $[seq_struct].description);
99  }
100  status = createseq(&$[seq_name], $[seq_struct].duration - $[seq_struct].ssi_time, off_$[seq_name]);
101  if (status != SUCCESS) {
102  ks_error("KS_SEQLENGTH (%s): createseq($[seq_name]) failed", $[seq_struct].description);
103  }
104 
105 #if defined(HOST_TGT)
106  /* Update sequence counter and get current sequence entry index */
107  status = updateIndex( &idx_$[seq_name] );
108  if (status != SUCCESS) {
109  ks_error("KS_SEQLENGTH (%s): updateIndex($[seq_name]) failed", $[seq_struct].description);
110  }
111  printDebug( DBLEVEL1, (dbLevel_t)seg_debug, "KS_SEQLENGTH",
112  "idx_$[seq_name] = %d\n", idx_$[seq_name] );
113  $[seq_struct].handle.index = idx_$[seq_name];
114 #endif
115  /* copy seqyence_enties to the KS_SEQ seq_struct */
116  $[seq_struct].handle.offset = off_$[seq_name];
117  $[seq_struct].handle.pulse = &$[seq_name];
118  } /* duration - ssi_time > 0 */
119 
120  } /* duration > 0 */
121  }
122  }
123 }
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
#define seq_name
STATUS predownload(void)
Definition: ksepi.e:228
STATUS cvinit(void)
Definition: ksepi.e:86

◆ calcPulseParams()

STATUS calcPulseParams ( int  p)

Mandatory GE function. Includes predownload.in

Return values
STATUSSUCCESS or FAILURE
283  {
284 
285  p = 0;
286  return SUCCESS;
287 
288 } /* calcPulseParams() */

◆ simscan()

STATUS simscan ( void  )

Simulate scan locations in simulation (WTools)

Return values
STATUSSUCCESS or FAILURE
299  {
300 
301 #ifndef PSD_HW
302 
303  int i, j;
304  int num_slice;
305  float z_delta; /* change in z_loc between slices */
306  float r_delta; /* change in r_loc between slices */
307  double alpha, beta, gamma; /* rotation angles about x, y, z respectively */
308 
309  num_slice = opslquant;
310 
311  r_delta = opfov / num_slice;
312  z_delta = opslthick + opslspace;
313 
314  ks_scan_info[0].optloc = - 0.5 * z_delta * (num_slice - 1);
315  ks_scan_info[0].oprloc = 0;
316 
317  for (i = 1; i < 9; i++)
318  ks_scan_info[0].oprot[i] = 0.0;
319 
320  switch (exist(opplane)) {
321  case PSD_AXIAL:
322  ks_scan_info[0].oprot[0] = 1.0;
323  ks_scan_info[0].oprot[4] = 1.0;
324  ks_scan_info[0].oprot[8] = 1.0;
325  break;
326  case PSD_SAG:
327  ks_scan_info[0].oprot[2] = 1.0;
328  ks_scan_info[0].oprot[4] = 1.0;
329  ks_scan_info[0].oprot[6] = 1.0;
330  break;
331  case PSD_COR:
332  ks_scan_info[0].oprot[2] = 1.0;
333  ks_scan_info[0].oprot[6] = 1.0;
334  ks_scan_info[0].oprot[7] = 1.0;
335  break;
336  case PSD_OBL:
337  alpha = PI / 4.0; /* rotation about x (applied first) */
338  beta = 0; /* rotation about y (applied 2nd) */
339  gamma = 0; /* rotation about z (applied 3rd) */
340  ks_scan_info[0].oprot[0] = cos(gamma) * cos(beta);
341  ks_scan_info[0].oprot[1] = cos(gamma) * sin(beta) * sin(alpha) -
342  sin(gamma) * cos(alpha);
343  ks_scan_info[0].oprot[2] = cos(gamma) * sin(beta) * cos(alpha) +
344  sin(gamma) * sin(alpha);
345  ks_scan_info[0].oprot[3] = sin(gamma) * cos(beta);
346  ks_scan_info[0].oprot[4] = sin(gamma) * sin(beta) * sin(alpha) +
347  cos(gamma) * cos(alpha);
348  ks_scan_info[0].oprot[5] = sin(gamma) * sin(beta) * cos(alpha) -
349  cos(gamma) * sin(alpha);
350  ks_scan_info[0].oprot[6] = -sin(beta);
351  ks_scan_info[0].oprot[7] = cos(beta) * sin(alpha);
352  ks_scan_info[0].oprot[8] = cos(beta) * cos(alpha);
353  break;
354  }
355 
356  for (i = 1; i < num_slice; i++) {
357  ks_scan_info[i].optloc = ks_scan_info[i - 1].optloc + z_delta;
358  ks_scan_info[i].oprloc = i * r_delta;
359  for (j = 0; j < 9; j++)
360  ks_scan_info[i].oprot[j] = ks_scan_info[0].oprot[j];
361  }
362 
363 #endif /* ifdef SIM */
364 
365  return SUCCESS;
366 
367 } /* simscan() */
float opfov
float opslthick
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ GEReq_init_gradspecs()

STATUS GEReq_init_gradspecs ( LOG_GRAD *  loggrd,
PHYS_GRAD *  phygrd,
float  srfact 
)

Initialize logical and physical gradient specifications

This function calls inittargets() to get the physical gradient characteristics from the MR-system, followed by a call to obloptimize() (slice angulation dependence) to get the logical gradient specifications for the current slice angulation.

The ramp times (loggrd.xrt/yrt/zrt) are quite conservative (and longer than the ramptimes for phygrd). Preliminary testing indicates that the difference between the loggrd and phygrad structs can be reduced by a factor of two (not very scientific!) as a standard measure.

For further control over the slewrate, the srfact argument is passed to ks_init_slewratecontrol(), which can both slow down and increase the gradient slewrate.

Parameters
[out]loggrdThe global logical gradient specification struct (dependent on slice angulation via global SCAN_INFO scan_info[] struct).
[out]phygrdThe global physical gradient struct
[in]srfact
Return values
STATUSSUCCESS or FAILURE
393  {
394  int initnewgeo = 1;
395 
396  /* default gradient specs */
398 
399  /* optimal loggrd based on current slice angulations */
400  if (obloptimize_epi(loggrd, phygrd, scan_info, exist(opslquant),
401  ((obl_method==PSD_OBL_RESTRICT) ? 4 /*oblique plane*/ : opphysplane), exist(opcoax), (int) obl_method,
402  exist(obl_debug), &initnewgeo, cfsrmode) == FAILURE) {
403  return ks_error("ks_init_loggrd: obloptimize failed");
404  }
405 
406  /* obloptimize() ramptimes too conservative, let's cut the difference
407  between loggrd.xrt and phygrd.xrt in half */
408  loggrd->xrt = (loggrd->xrt - phygrd->xrt) / 2 + phygrd->xrt;
409  loggrd->yrt = (loggrd->yrt - phygrd->yrt) / 2 + phygrd->yrt;
410  loggrd->zrt = (loggrd->zrt - phygrd->zrt) / 2 + phygrd->zrt;
411 
412  /* reduce slewrate if srfact < 1 */
413  if (ks_init_slewratecontrol(loggrd, phygrd, srfact) == FAILURE)
414  return FAILURE;
415 
416  return SUCCESS;
417 
418 } /* GEReq_init_gradspecs() */
STATUS inittargets(LOG_GRAD *lgrad, PHYS_GRAD *pgrad)
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int obl_method
Definition: GERequired.e:234
PHYS_GRAD phygrd
LOG_GRAD loggrd
STATUS obloptimize_epi(LOG_GRAD *lgrad, PHYS_GRAD *pgrad, SCAN_INFO *scaninfotab, INT slquant, INT plane_type, INT coaxial, INT method, INT debug, INT *newgeo, INT srmode)
int obl_debug
Definition: GERequired.e:233
STATUS ks_init_slewratecontrol(LOG_GRAD *loggrd, PHYS_GRAD *phygrd, float srfact) WARN_UNUSED_RESULT
Changes existing (globally used) loggrd and phygrd structs (set up by inittargets() in e...
Definition: KSFoundation_host.c:123
int cfsrmode

◆ GEReq_init_accelUI()

STATUS GEReq_init_accelUI ( int  integeraccel,
int  maxaccel 
)

Sets up the menu for parallel imaging (ARC or ASSET) with max/min range

Parameters
[in]integeraccelFlag to make acceleration menu contain only integer acceleration factors enums: KS_ARCMENU_FRACTACCEL (0), KS_ARCMENU_INTACCEL (1)
[in]maxaccelMaximum allowed acceleration factor for the sequence
Return values
STATUSSUCCESS or FAILURE
432  {
433 
434  /* Acceleration menu */
435  cfaccel_ph_maxstride = maxaccel;
436  cvmax(opaccel_ph_stride, cfaccel_ph_maxstride);
437  avminaccel_ph_stride = 1.0;
438  avmaxaccel_ph_stride = cfaccel_ph_maxstride;
439  piarccoilrestrict = 1; /* disable ARC option for single-channel coil (cf. epic.h) */
440 
441  if (KS_3D_SELECTED) { /* PSD_3D or PSD_3DM */
442  cfaccel_sl_maxstride = maxaccel;
443  cvmax(opaccel_sl_stride, cfaccel_sl_maxstride);
444  avminaccel_sl_stride = 1.0;
445  avmaxaccel_sl_stride = cfaccel_sl_maxstride;
446  }
447 
448  if ((oparc || opasset == ASSET_SCAN) && maxaccel > 1) {
449  if (integeraccel) {
450  piaccel_phnub = 1 + maxaccel;
451  piaccel_phval2 = 1.0;
452  piaccel_phval3 = 2.0;
453  piaccel_phval4 = 3.0;
454  piaccel_phval5 = 4.0;
455  piaccel_phval6 = 5.0;
456  piaccel_phedit = 0; /* don't allow user to type in value */
457  } else {
458  piaccel_phnub = IMin(2, 6, maxaccel * 2);
459  piaccel_phval2 = 1.0;
460  piaccel_phval3 = 1.5;
461  piaccel_phval4 = 2.0;
462  piaccel_phval5 = 2.5;
463  piaccel_phval6 = 3.0;
464  piaccel_phedit = 1;
465  }
466  piaccel_ph_stride = 2.0;
467  if (KS_3D_SELECTED) {
468  if (integeraccel) {
469  piaccel_slnub = 1 + maxaccel;
470  piaccel_slval2 = 1.0;
471  piaccel_slval3 = 2.0;
472  piaccel_slval4 = 3.0;
473  piaccel_slval5 = 4.0;
474  piaccel_slval6 = 5.0;
475  piaccel_sledit = 0; /* don't allow user to type in value */
476  } else {
477  piaccel_slnub = IMin(2, 6, maxaccel * 2);
478  piaccel_slval2 = 1.0;
479  piaccel_slval3 = 1.5;
480  piaccel_slval4 = 2.0;
481  piaccel_slval5 = 2.5;
482  piaccel_slval6 = 3.0;
483  piaccel_sledit = 1;
484  }
485  piaccel_sl_stride = 1.0;
486  } else {
487  piaccel_slnub = 0;
488  }
489  } else {
490  piaccel_phnub = 0;
491  piaccel_slnub = 0;
492  cvoverride(opaccel_ph_stride, 1.0, PSD_FIX_OFF, PSD_EXIST_OFF);
493  cvoverride(opaccel_sl_stride, 1.0, PSD_FIX_OFF, PSD_EXIST_OFF);
494  }
495 
496  return SUCCESS;
497 
498 } /* GEReq_init_accelUI() */
#define KS_3D_SELECTED
Definition: KSFoundation.h:177

◆ GEReq_eval_TRrange()

STATUS GEReq_eval_TRrange ( int *  slperpass,
int *  timetoadd_perTR,
int  requested_minacqs,
int  mintr,
int  maxtr,
KS_SEQ_COLLECTION seqcollection,
int(*)(int, int, void **)  play_loop,
int  nargs,
void **  args 
)

Calculate the number of slices per TR and TR padding time (2D imaging)

This function calculates the number of slices that can fit in one TR (optr) based on the duration and occurences of the sequence modules in the sequence collection (KS_SEQ_COLLECTION) determined by calling the sequence sliceloop (wrapper) function.

As the number of arguments to the sequence's sliceloop is psd-dependent, the function pointer play_loop must be a wrapper function to the sliceloop function taking standardized input arguments (int) nargs and (void **) args. This sliceloop wrapper function must be on the form: int sliceloop_nargs(int slperpass, int nargs, void **args); returning the duration in [us] to play out slperpass number of slices. If the sliceloop function does not need any additional input arguments, nargs = 0, and args = NULL.

The minimum allowed TR is determined by ks_eval_mintr(), which honors SAR/heating limitations. If opautotr = 1, optr will be updated here, otherwise if optr is too short, an error will be returned to the operator.

The calling function can specify the minimum acqs that are allowed, as well as a minimum and maximum TR interval. Setting maxtr = 0 disables the upper TR limit. Setting requested_minacqs <= 1, disables the min acqs requirement.

This function should be called at the end of cveval() after all sequence modules have been set up and dry-runned on host by calling each sequence module's ****_pg() function. See also the documentation for KS_SEQ_CONTROL and KS_SEQ_COLLECTION.

Parameters
[out]slperpassNumber of slices that can fit within each TR
[out]timetoadd_perTRThe total time in [us] that must be distributed manually to one or more sequence modules after the call to GEReq_eval_TR() in order to meet the desired TR
[in]requested_minacqsThe desired minimum number of acquisitions (passes)
[in]mintrLowest allowed TR in [us]
[in]maxtrHighest allowed TR in [us]. 0: Disabled
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]play_loopFunction pointer to (the wrapper function to) the sliceloop function of the sequence
[in]nargsNumber of extra input arguments to the sliceloop wrapper function.
[in]argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's sliceloop function
Return values
STATUSSUCCESS or FAILURE
545  {
546  STATUS status;
547  int numacqs = 0;
548  int i;
549  int numrfexclocations = (KS_3D_SELECTED) ? exist(opvquant) : exist(opslquant);
550  int slicetime;
551  int nslices_perTR = KS_NOTSET;
552  int nslices_shortest_scantime = KS_NOTSET;
553  int lowest_scantime = KS_NOTSET;
554  int singleslice_time = KS_NOTSET;
555  int requested_maxslices = KS_NOTSET;
556  int maxslices_time = KS_NOTSET;
557 
558  /* if another function has already performed TR timing calcs, don't do it again */
559  if (seqcollection->evaltrdone == TRUE) {
560  return SUCCESS;
561  }
562 
563  if (seqcollection == NULL || seqcollection->numseq == 0) {
564  return ks_error("%s: Please add pulse sequence modules to the sequence collection before calling this function", __FUNCTION__);
565  }
566 
567  if (mintr < 0 || maxtr < 0) {
568  return ks_error("%s: min/max TR cannot be negative", __FUNCTION__);
569  } else if ((maxtr > 0) && (maxtr <= mintr)) {
570  return ks_error("%s: max TR must be > minTR, or 0 (disabled)", __FUNCTION__);
571  }
572 
573  /* make sure seqctrl.duration at least equal to seqctrl.min_duration */
575  if (status != SUCCESS) return FAILURE;
576 
577  singleslice_time = ks_eval_mintr(1, seqcollection, ks_gheatfact, play_loop, nargs, args);
578  if (singleslice_time <= 0) return FAILURE;
579 
580  if ((maxtr > 0) && (maxtr < singleslice_time)) {
581  return ks_error("%s: Max TR must be > %.1f ms", __FUNCTION__, singleslice_time / 1000.0);
582  }
583  if ((mintr > 0) && (mintr < singleslice_time)) {
584  return ks_error("%s: Min TR must be > %.1f ms", __FUNCTION__, singleslice_time / 1000.0);
585  }
586  if ((maxtr > 0) && ((maxtr - mintr) < singleslice_time)) {
587  return ks_error("%s: The TR interval must be > %.1f ms", __FUNCTION__, singleslice_time / 1000.0);
588  }
589 
590  /* #acqs cannot exceed #slices. If sequential scanning, #acqs = #slices */
591  if (requested_minacqs < 1) {
592  requested_minacqs = 1;
593  } else if ((requested_minacqs > numrfexclocations) || (opirmode == TRUE)) {
594  requested_minacqs = numrfexclocations;
595  }
596  requested_maxslices = CEIL_DIV(numrfexclocations, requested_minacqs);
597  maxslices_time = ks_eval_mintr(requested_maxslices, seqcollection, ks_gheatfact, play_loop, nargs, args);
598 
599 
600 
601  if (opautotr) { /* AutoTR: User selected pitrval2 = PSD_MINIMUMTR */
602 
603  if (maxtr > 0 || mintr > 0) { /* in-range autoTR */
604 
605  /* Check which combination that results in the lowest scan time, and max/min # slices in range */
606  for (i = 1; i <= numrfexclocations; i++) {
607  numacqs = CEIL_DIV(numrfexclocations, i);
608  slicetime = ks_eval_mintr(i, seqcollection, ks_gheatfact, play_loop, nargs, args);
609  if (slicetime >= mintr && (maxtr == 0 || slicetime <= maxtr) && (numacqs >= requested_minacqs)) {
610  if (lowest_scantime == KS_NOTSET) {
611  nslices_shortest_scantime = i;
612  lowest_scantime = slicetime * numacqs;
613  } else if (slicetime * numacqs <= lowest_scantime * 1.01) {
614  /* 1.01 to avoid round-off effects of slicetime and to slightly favor fewer acqs and longer TRs
615  when the scantime is nearly identical */
616  nslices_shortest_scantime = i;
617  lowest_scantime = slicetime * numacqs;
618  }
619  }
620  }
621 
622  if (lowest_scantime == KS_NOTSET) {
623  /* failed to find solution within the interval, the range is probably too high for the set
624  of slices. Need to add padding to reach mintr. This
625  is done by setting optr = avmintr = mintr (see also timetoadd_perTR below)*/
626  if (maxslices_time < mintr) {
627  nslices_perTR = requested_maxslices;
628  avmintr = mintr;
629  } else {
630  return ks_error("%s: Programming error", __FUNCTION__);
631  }
632  } else {
633  nslices_perTR = nslices_shortest_scantime;
634  avmintr = ks_eval_mintr(nslices_perTR, seqcollection, ks_gheatfact, play_loop, nargs, args);
635  }
636 
637  } else { /* minimum TR (using requested_minacqs) */
638 
639  nslices_perTR = requested_maxslices;
640  avmintr = ks_eval_mintr(nslices_perTR, seqcollection, ks_gheatfact, play_loop, nargs, args);
641 
642  }
643 
644  avmaxtr = avmintr;
645  cvoverride(optr, avmintr, PSD_FIX_ON, PSD_EXIST_ON);
646 
647  } else { /* Manual TR */
648 
649  avmintr = singleslice_time;
650  avmaxtr = _optr.maxval;
651 
652  /* how many slices can we MAXIMALLY fit in one TR ? */
653  if (opirmode == 1) { /* sequential */
654  nslices_perTR = 1;
655  } else {
656  if (existcv(optr)) {
657  if (optr < avmintr)
658  return ks_error("%s: Increase the TR to %.1f ms", __FUNCTION__, avmintr / 1000.0);
659  if ((mintr > 0) && (optr < mintr))
660  return ks_error("%s: Increase the TR to %.1f ms", __FUNCTION__, mintr / 1000.0);
661  if ((maxtr > 0) && (optr > maxtr))
662  return ks_error("%s: Decrease the TR to %.1f ms", __FUNCTION__, maxtr / 1000.0);
663  }
664  nslices_perTR = ks_eval_maxslicespertr(exist(optr), seqcollection, ks_gheatfact, play_loop, nargs, args);
665  nslices_perTR = IMax(2, 1, nslices_perTR); /* safeguard against < 1 */
666  }
667 
668  } /* Auto/Manual TR */
669 
670 
671  /* how many acqs (runs) do we need to get all prescribed slices ? */
672  numacqs = CEIL_DIV(numrfexclocations, nslices_perTR);
673 
674  /* how many slices SHOULD we play out per pass (keeping numrfexclocations and numacqs)?
675  This may be less than nslices_perTR depending on divisibility */
676  *slperpass = CEIL_DIV(numrfexclocations, numacqs); /* round up */
677 
678  /* run once more with the actual number of slices per TR, mostly so that ks_eval_gradrflimits() will set the
679  description of `optr` correctly */
680  ks_eval_mintr(*slperpass, seqcollection, ks_gheatfact, play_loop, nargs, args);
681 
682  /* run before each call to function pointer `play_loop()` (next line) to set all `seqctrl.ninst` to 0 */
684 
685  /* Update seqcollection.seqctrl[*].ninst given '*slperpass' number of slices
686  time [us] for one sequence playout incl. the SSI time and necessary dead time to
687  make up the expected TR. To be used in KS_SEQLENGTH() in pulsegen() */
688  *timetoadd_perTR = exist(optr) - play_loop(*slperpass, nargs, args);
689 
690  /* prevent further addition of new sequence modules */
692 
693  /* Flag that we have completed this function */
694  seqcollection->evaltrdone = TRUE;
695 
696 
697 
698  /* Set UI and advisory panel variables */
699  avail_image_time = RDN_GRD(exist(optr));
701  ihtr = act_tr; /* image header TR */
702 
703  avminslquant = 1;
704  if (KS_3D_SELECTED == FALSE) {
705  avmaxslquant = nslices_perTR; /* UI value ("Max # Slices:") */
706  avmaxacqs = numacqs; /* UI value ("# of Acqs:") */
707  } else {
708  avmaxslquant = 2048;
709  avmaxacqs = 1;
710  }
711 
712  return SUCCESS;
713 
714 } /* GEReq_eval_TRrange() */
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int mode
Definition: KSFoundation.h:1301
STATUS ks_eval_seqcollection_durations_atleastminimum(KS_SEQ_COLLECTION *seqcollection) WARN_UNUSED_RESULT
Assures the .duration fields of all sequence modules being part of the sequence collection (KS_SEQ_CO...
Definition: KSFoundation_host.c:4348
ifndef ACT_TR_EXISTS int act_tr
Definition: GERequired.e:210
int evaltrdone
Definition: KSFoundation.h:1303
float ks_gheatfact
Definition: GERequired.e:244
int avail_image_time
Definition: GERequired.e:208
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
void ks_eval_seqcollection_resetninst(KS_SEQ_COLLECTION *seqcollection)
Set the .nseqinstances field of each sequence module (KS_SEQ_CONTROL) equal to 0
Definition: KSFoundation_host.c:4590
Definition: KSFoundation.h:1974
int ks_eval_mintr(int nslices, KS_SEQ_COLLECTION *seqcollection, float gheatfact, int(*play_loop)(int, int, void **), int nargs, void **args)
Returns the minimum TR based on the content of a slice loop, adding additional time due to SAR and ha...
Definition: KSFoundation_host.c:4554
int numseq
Definition: KSFoundation.h:1300
int ks_eval_maxslicespertr(int TR, KS_SEQ_COLLECTION *seqcollection, float gheatfact, int(*play_loop)(int, int, void **), int nargs, void **args)
Returns the maximum number of slices that can be played out in one TR, honoring SAR and hardware cons...
Definition: KSFoundation_host.c:4567

◆ GEReq_eval_TR()

STATUS GEReq_eval_TR ( int *  slperpass,
int *  timetoadd_perTR,
int  requested_minacqs,
KS_SEQ_COLLECTION seqcollection,
int(*)(int, int, void **)  play_loop,
int  nargs,
void **  args 
)
720  {
721 
722  return GEReq_eval_TRrange(slperpass, timetoadd_perTR, requested_minacqs, 0, 0, seqcollection, play_loop, nargs, args);
723 
724 
725 } /* GEReq_eval_TR() */
STATUS GEReq_eval_TRrange(int *slperpass, int *timetoadd_perTR, int requested_minacqs, int mintr, int maxtr, KS_SEQ_COLLECTION *seqcollection, int(*play_loop)(int, int, void **), int nargs, void **args)
Calculate the number of slices per TR and TR padding time (2D imaging)
Definition: GERequired.e:544
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80

◆ GEReq_eval_rfscaling()

STATUS GEReq_eval_rfscaling ( KS_SEQ_COLLECTION seqcollection)

Performs RF scaling of all RF pulses in the KS_SEQ_COLLECTION and Prescan

RF scaling is a complicated process across RF pulses in scan (multiple sequence modules) and prescan, where the desired flip angles should be met partly using the maxB1 info for each RF pulse and scale it relative to the prescan result. This is done via a combination of scan and prescan attenuation factors (xmtaddScan) in the entry_point_table[], an extra global scaling factor, and change of the (instruction) amplitude of each RF pulse.

This function performs all these tasks using a KS_SEQ_COLLECTION as input. The sequence collection struct contains one KS_SEQ_CONTROL struct for each sequence module, which via the field gradrf.rfptr[] has access to all KS_RF objects in the sequence module. As the ***_pg() function for each sequence module should have been called prior to this function, the number of occurrences of each RF pulse is known. Moreover, the rfstat specification for every RF pulse is located in: seqcollection->seqctrl[]->gradrf->rfptr[]->rf.rfpulse which is used by ks_eval_seqcollection2rfpulse() to rewrite the global rfpulse[] struct array required by GE's RF scaling functions peakB1() and setScale().

At the end of this function, the seqcollection mode is locked, preventing accidental addition of new sequence modules to the seqcollection using ks_eval_addtoseqcollection(). Moreover, each sequence module will have its rfscalingdone field set to TRUE to signal to ks_pg_rf() that the RF pulse belonging to that sequence module has indeed been RF scaled properly. This extra safety mechanism makes it difficult to use ks_pg_rf() without first passing through this function and have the seqcollection struct set up.

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
Return values
STATUSSUCCESS or FAILURE
758  {
759  int i;
760  STATUS status;
761 
762 
763  if (seqcollection == NULL || seqcollection->numseq == 0) {
764  return ks_error("%s: Please add pulse sequence modules to the sequence collection before calling this function", __FUNCTION__);
765  }
766 
767  /* use global rfpulse[] array (that is also featuring in Prescan.e) */
768  for (i = 0; i < KS_MAXUNIQUE_RF; i++) {
769  rfpulse[i].activity = 0;
770  }
771 
772  /* Update the global RF pulse array rfpulse[] with the contents of the RF pulses in the sequence modules.
773  This also includes resetting all .activity fields to zero for the first KS_MAXUNIQUE_RF elements in rfpulse[] */
775  if (status != SUCCESS) return status;
776 
777 
778  /* find the peak B1 for each entry point and the max B1 across all entry points */
779  status = findMaxB1Seq(&maxB1Seq, maxB1, MAX_ENTRY_POINTS, rfpulse, RF_FREE);
780  if (status != SUCCESS) {
781  return ks_error("%s: findMaxB1Seq() failed", __FUNCTION__);
782  }
783 
784  /* RF: How much do we need to attenuate the RF pulses in scan. */
785  double my_xmtaddScan = -200 * log10(maxB1[L_SCAN] / maxB1Seq) + getCoilAtten();
786  if (my_xmtaddScan > cfdbmax) {
787  extraScale = (float) pow(10.0, (cfdbmax - my_xmtaddScan) / 200.0); /* N.B.: 'extraScale' is declared as CV in Prescan.e */
788  my_xmtaddScan = cfdbmax;
789  } else {
790  extraScale = 1.0;
791  }
792 
793  /* RF: Scale the rfpulse amplitudes */
794  status = setScale(L_SCAN, RF_FREE, rfpulse, maxB1[L_SCAN], extraScale);
795  if (status != SUCCESS) {
796  return ks_error("%s: setScale failed", __FUNCTION__);
797  }
798 
799  /* fill entry_point_table */
800  status = entrytabinit(entry_point_table, (int)ENTRY_POINT_MAX);
801  if (status != SUCCESS) {
802  return ks_error("%s: entrytabinit() failed", __FUNCTION__);
803  }
804  strcpy( entry_point_table[L_SCAN].epname, "scan");
805  entry_point_table[L_SCAN].epxmtadd = (short)rint( (double) my_xmtaddScan);
806  entry_point_table[L_SCAN].epstartrec = rhdab0s;
807  entry_point_table[L_SCAN].ependrec = rhdab0e;
808 #if EPIC_RELEASE < 29
809  entry_point_table[L_SCAN].epfastrec = 0;
810 #endif
811  entry_point_table[L_APS2] = entry_point_table[L_MPS2] = entry_point_table[L_SCAN];
812  strcpy(entry_point_table[L_APS2].epname, "aps2");
813  strcpy(entry_point_table[L_MPS2].epname, "mps2");
814 
815  /* Prescan: Final RF scaling of the Prescan entries, using the maxB1[] and maxB1Seq values computed above */
816 
817  /* prevent further addition of new sequence modules */
819 
820  /* Flag each sequence module that RF scaling has been done */
821  for (i = 0; i < seqcollection->numseq; i++) {
823  }
824 
825  return SUCCESS;
826 
827 } /* GEReq_eval_rfscaling() */
#define KS_MAXUNIQUE_RF
Definition: KSFoundation.h:187
RF_PULSE rfpulse[RF_FREE]
Definition: grad_rf_empty.h:55
#define MAX_ENTRY_POINTS
Definition: GERequired.e:142
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int rfscalingdone
Definition: KSFoundation.h:1139
int mode
Definition: KSFoundation.h:1301
KS_SEQ_CONTROL * seqctrlptr[KS_MAXUNIQUE_SEQUENCES]
Definition: KSFoundation.h:1306
float maxB1Seq
Definition: GERequired.e:269
float maxB1[MAX_ENTRY_POINTS]
Definition: GERequired.e:269
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
Definition: KSFoundation.h:1974
int numseq
Definition: KSFoundation.h:1300
STATUS ks_eval_seqcollection2rfpulse(RF_PULSE *rfpulse, KS_SEQ_COLLECTION *seqcollection)
(Internal use) Sets up GE&#39;s rfpulse[] array from the contents of a KS_SEQ_COLLECTION struct...
Definition: KSFoundation_host.c:4651

◆ GEReq_eval_checkTR_SAR_calcs()

STATUS GEReq_eval_checkTR_SAR_calcs ( KS_SEQ_COLLECTION seqcollection,
int  intended_time 
)

Checks that sequence modules sum up to TR, honoring SAR/heating limits

This function is called by GEReq_eval_checkTR_SAR() (non-inversion use) and ksinv_eval_checkTR_SAR() (inversion use) to check that the sequence modules played out in the slice loop sum up to the specified TR (optr) accounting for SAR/heating limits. Moreover, the SAR values are updated in the UI, and the CV ks_sarcheckdone is set to TRUE. This CV is set to FALSE in GEReq_cvinit() and check whether it is TRUE in GEReq_predownload() to make sure SAR calculation have been performed before scanning.

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]intended_timeUsually repetition time (optr) if this function was called from GEReq_eval_checkTR_SAR(), but should correspond to the intended time to play the corresponding number of sequence instances now set in seqcollection[]->seqctrl.ninst
Return values
STATUSSUCCESS or FAILURE
848  {
849  KS_SAR sar;
850  int duration_withinlimits;
851  int nettime;
852  STATUS status;
853 
854  if (seqcollection->evaltrdone == FALSE) {
855  return ks_error("%s: Please call GEReq_eval_TR() before calling this function", __FUNCTION__);
856  }
857 
858  /* Print out the sequence collection time table. In simulation it appears in the WTools main window */
859 #ifdef PSD_HW
860  FILE *fp = fopen("/usr/g/mrraw/seqcollection.txt", "w");
862  fclose(fp);
863 #else
865 #endif
866 
867  /*
868  The duration based on the sequence collection struct, which is the product .nseqinstances and .duration fields in each sequence
869  modules, summed over all sequence modules.
870  The .nseqinstances field becomes > 0 by the call to: GEReq_eval_TR()->ks_eval_mintr()->play_loop()->ks_scan_playsequence()
871  The .duration field is initially set to .min_duration by GEReq_eval_TR()->ks_eval_seqcollection_durations_atleastminimum(), but the
872  .duration field of at least one sequence module should have been set larger than its .min_duration based on the amount of
873  timetoadd_perTR returned by GEReq_eval_TR() */
875  if (nettime <= 0) {
876 
877  return FAILURE;
878  }
879 
880  /* duration_withinlimits = nettime + grad/RF SAR/heat penalty time */
881  duration_withinlimits = ks_eval_gradrflimits(&sar, seqcollection, ks_gheatfact);
882  if (duration_withinlimits == KS_NOTSET) {
883  return FAILURE;
884  }
885 
886  /* Make sure the global RF pulse array rfpulse[] is updated with the contents of the RF pulses in the sequence modules.
887  This also includes resetting all .activity fields to zero for the first KS_MAXUNIQUE_RF elements in rfpulse[] */
889  if (status != SUCCESS) return status;
890 
891 
892  /* report to UI */
893  piasar = (float) sar.average;
894  picasar = (float) sar.coil;
895  pipsar = (float) sar.peak;
896  pib1rms = (float) sar.b1rms;
897 
898  if (existcv(opslquant) == FALSE) {
899  /* if #slices has not been set yet, hold on complaining */
900  return SUCCESS;
901  }
902 
903  if (nettime < duration_withinlimits) {
904  return ks_error("%s: Duration of seq. modules (%d) < grad/rf limits (%d)", __FUNCTION__, nettime, duration_withinlimits);
905  }
906  if (nettime - intended_time > MAX_TR_OVERSHOOT) {
907  /* small excess in nettime is expected due to roundups of .duration to nearest 4us, but we cannot accept too much */
908  /* return */ ks_error("%s: Duration of seq. modules (%d) %d us too long", __FUNCTION__, nettime, nettime - intended_time);
909  }
910  if (intended_time - nettime > MAX_TR_UNDERSHOOT) {
911  /* return */ ks_error("%s: Duration of seq. modules (%d) %d us too short", __FUNCTION__, nettime, intended_time - nettime);
912  }
913 
914 
915 #if EPIC_RELEASE >= 27
916  status = setupPowerMonitor(&entry_point_table[L_SCAN], sar.average);
917 #else
918  status = setupPowerMonitor(&entry_point_table[L_SCAN], L_SCAN, RF_FREE, rfpulse,
919  nettime, sar.average, sar.coil, sar.peak);
920 #endif
921  if (status != SUCCESS) {
922  return ks_error("%s: setupPowerMonitor failed", __FUNCTION__);
923  }
924 
925  /* prevent further addition of new sequence modules */
927 
928 
929  /* Flag that SAR check has been done */
930  ks_sarcheckdone = TRUE;
931 
932  return SUCCESS;
933 
934 } /* GEReq_eval_checkTR_SAR_calcs() */
int ks_eval_gradrflimits(KS_SAR *sar, KS_SEQ_COLLECTION *seqcollection, float gheatfact)
Returns the time required to play out a certain number of sequence modules over some interval...
Definition: KSFoundation_host.c:4370
double b1rms
Definition: KSFoundation.h:1319
RF_PULSE rfpulse[RF_FREE]
Definition: grad_rf_empty.h:55
#define KS_NOTSET
Definition: KSFoundation.h:103
double average
Definition: KSFoundation.h:1316
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
double coil
Definition: KSFoundation.h:1317
void ks_print_seqcollection(KS_SEQ_COLLECTION *seqcollection, FILE *fp)
Print out the duration of each sequence module in the sequence collection to a file pointerBesides pr...
Definition: KSFoundation_host.c:5078
int mode
Definition: KSFoundation.h:1301
#define MAX_TR_UNDERSHOOT
Definition: GERequired.e:146
int ks_eval_seqcollection_gettotalduration(KS_SEQ_COLLECTION *seqcollection)
Returns the total duration of the sequence collection
Definition: KSFoundation_host.c:4603
Struct to keep SAR parameters together. Used in ks_eval_gradrflimits() and GEReq_eval_checkTR_SAR_cal...
Definition: KSFoundation.h:1315
#define MAX_TR_OVERSHOOT
Definition: GERequired.e:145
int evaltrdone
Definition: KSFoundation.h:1303
float ks_gheatfact
Definition: GERequired.e:244
int ks_sarcheckdone
Definition: GERequired.e:219
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
Definition: KSFoundation.h:1974
double peak
Definition: KSFoundation.h:1318
STATUS ks_eval_seqcollection2rfpulse(RF_PULSE *rfpulse, KS_SEQ_COLLECTION *seqcollection)
(Internal use) Sets up GE&#39;s rfpulse[] array from the contents of a KS_SEQ_COLLECTION struct...
Definition: KSFoundation_host.c:4651

◆ GEReq_eval_checkTR_SAR()

STATUS GEReq_eval_checkTR_SAR ( KS_SEQ_COLLECTION seqcollection,
int  nslices,
int(*)(int, int, void **)  play_loop,
int  nargs,
void **  args 
)

Runs the slice loop and validates TR and SAR/hardware limits

This function first makes sure that the .nseqinstances field for each sequence module in the sequence collection corresponds to the number of times played out in the sequence's sliceloop function.

In simulation (WTools), ks_print_seqcollection() will print out a table of the sequence modules in the sequence collection in the WToolsMgd window.

Finally, GEReq_eval_checkTR_SAR_calcs() is called to check that the TR is correct and within SAR/hardware limits.

N.B.: For inversion sequences, ksinv_eval_checkTR_SAR() is used to do the same thing, with the difference that ksinv_scan_sliceloop() is used instead.

Parameters
[in]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]nslicesNumber of slices in TR
[in]play_loopFunction pointer to (the wrapper function to) the sliceloop function
[in]nargsNumber of extra input arguments to the sliceloop wrapper function.
[in]argsVoid pointer array pointing to the variables containing the actual values needed for the sliceloop function
Return values
STATUSSUCCESS or FAILURE
963  {
964 
965  if (seqcollection == NULL || seqcollection->numseq == 0) {
966  return ks_error("%s: Please add pulse sequence modules to the sequence collection before calling this function", __FUNCTION__);
967  }
968 
969  /* set all `seqctrl.nseqinstances` to 0 */
971  play_loop(nslices, nargs, args); /* => seqctrl.nseqinstances = # times each seq. module has been played out */
972 
974 
975 } /* GEReq_eval_checkTR_SAR() */
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
STATUS GEReq_eval_checkTR_SAR_calcs(KS_SEQ_COLLECTION *seqcollection, int intended_time)
Checks that sequence modules sum up to TR, honoring SAR/heating limits
Definition: GERequired.e:848
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
void ks_eval_seqcollection_resetninst(KS_SEQ_COLLECTION *seqcollection)
Set the .nseqinstances field of each sequence module (KS_SEQ_CONTROL) equal to 0
Definition: KSFoundation_host.c:4590
int numseq
Definition: KSFoundation.h:1300

◆ GEReq_predownload_store_sliceplan()

STATUS GEReq_predownload_store_sliceplan ( KS_SLICE_PLAN  slice_plan)

Sets mandatory global GE arrays for data acquisition

The following global GE arrays are set based on slperpass (arg 1) and global op** variables:

  • data_acq_order[]: Critical for scanning
  • rsp_info[]: Copied from scan_info[] (the graphically prescibed slices), for conformance. Is a temporally sorted version of scan_info[] with integer rotation matrices. Not needed for scanning.
  • rsptrigger[]: Set to TRIG_INTERN for now.

data_acq_order[] is only available on HOST, why this function also copies data_acq_order[] to ks_data_acq_order[], which is an ipgexport array accessible on both HOST and TGT. This can be used by ks_scan_getsliceloc() to be independent on rsp_info[] during scan.

The slice plan is stored as a text file ("ks_sliceplan.txt") in the current directory in simulation and in /usr/g/mrraw on the MR scanner by calling ks_print_sliceplan().

Parameters
[in]slice_planThe current slice plan (KS_SLICE_PLAN) set up for the sequence (see ks_calc_sliceplan())
Return values
STATUSSUCCESS or FAILURE
1001  {
1002  int i, j, time;
1003 
1004  if (slice_plan.npasses == 0) {
1005  return ks_error("%s: #acqs (.npasses) cannot be 0", __FUNCTION__);
1006  }
1007 
1008  if (CEIL_DIV(slice_plan.nslices, slice_plan.nslices_per_pass) != slice_plan.npasses) {
1009  return ks_error("%s: inconsistent slice plan - #acqs", __FUNCTION__);
1010  }
1011 
1012  if (!KS_3D_SELECTED && slice_plan.nslices != exist(opslquant)) {
1013  return ks_error("%s: inconsistent slice plan - #slices", __FUNCTION__);
1014  }
1015 
1016  /* initialize rsp_info, rtsprot and rsptrigger */
1017  for (i = 0; i < DATA_ACQ_MAX; i++) {
1018  rsp_info[i].rsptloc = 0;
1019  rsp_info[i].rsprloc = 0;
1020  rsp_info[i].rspphasoff = 0;
1021  rsptrigger[i] = TRIG_INTERN;
1022  for (j = 0; j < 9; j++)
1023  rsprot[i][j] = 0;
1024  }
1025 
1026  /* copy to global data_acq_order, which must be correct for main sequence or scan will not start */
1027  for (i = 0; i < slice_plan.nslices; i++) {
1028  data_acq_order[i].slloc = slice_plan.acq_order[i].slloc;
1029  data_acq_order[i].slpass = slice_plan.acq_order[i].slpass;
1030  data_acq_order[i].sltime = slice_plan.acq_order[i].sltime;
1031  } /* for slice locations */
1032 
1033  for (i = slice_plan.nslices; i < SLICE_FACTOR*DATA_ACQ_MAX; i++) {
1034  data_acq_order[i].slloc = data_acq_order[i % slice_plan.nslices].slloc;
1035  data_acq_order[i].slpass = data_acq_order[i % slice_plan.nslices].slpass;
1036  data_acq_order[i].sltime = data_acq_order[i % slice_plan.nslices].sltime;
1037 #ifdef UNDEF
1038  data_acq_order[i].slloc = 0;
1039  data_acq_order[i].slpass = 0;
1040  data_acq_order[i].sltime = 0;
1041 #endif
1042  } /* for rest of data_acq_order */
1043 
1044  time = 0;
1045  for (i = 0; i < slice_plan.npasses; ++i) {
1046  for (j = 0; j < slice_plan.nslices_per_pass; ++j) {
1047  int slloc = ks_scan_getsliceloc(&slice_plan, i, j);
1048  if (slloc == KS_NOTSET) {continue;}
1049 
1050  rsp_info[time].rsptloc = scan_info[slloc].optloc;
1051  rsp_info[time].rsprloc = scan_info[slloc].oprloc;
1052  rsp_info[time].rspphasoff = scan_info[slloc].opphasoff;
1053 
1054  scale(&scan_info[slloc].oprot, &rsprot[time], 1, &loggrd, &phygrd, 0);
1055 
1056  /* Future: here we could change to a variable to support gating. TRIG_ECG, TRIG_AUX etc */
1057  rsptrigger[time] = TRIG_INTERN;
1058 
1059  ++time;
1060  }
1061  }
1062 
1063  /* Save acquisition table to disk for debugging */
1064 #ifdef PSD_HW
1065  FILE *daqfp = fopen("/usr/g/mrraw/ks_sliceplan.txt", "w");
1066 #else
1067  FILE *daqfp = fopen("./ks_sliceplan.txt", "w");
1068 #endif
1069 
1070  ks_print_sliceplan(slice_plan, daqfp);
1071  fclose(daqfp);
1072 
1073  STATUS status = calcChecksumScanInfo(&chksum_scaninfo, scan_info, slice_plan.nslices, psdcrucial_debug);
1074  if (status != SUCCESS) {
1075  epic_error(1, "GEReq...sliceplan(): PSD data integrity violation detected in PSD",
1076  EM_PSD_PSDCRUCIAL_DATA_FAILURE, EE_ARGS(1), SYSLOG_ARG);
1077  return status;
1078  }
1079 
1080  /* set GE acqs and slquant1 CVs for look and feel */
1081  _slquant1.fixedflag = 0;
1082  _acqs.fixedflag = 0;
1083  slquant1 = slice_plan.nslices_per_pass;
1084  acqs = slice_plan.npasses;
1085  /* prescan */
1086  picalmode = 0;
1087  pislquant = slquant1;
1088 
1089  return SUCCESS;
1090 
1091 }
DATA_ACQ_ORDER acq_order[SLICE_FACTOR *DATA_ACQ_MAX]
Definition: KSFoundation.h:1354
#define KS_NOTSET
Definition: KSFoundation.h:103
void ks_print_sliceplan(const KS_SLICE_PLAN slice_plan, FILE *fp)
Writes a KS_SLICE_PLAN to a file pointer
Definition: KSFoundation_host.c:5097
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
PHYS_GRAD phygrd
int nslices_per_pass
Definition: KSFoundation.h:1353
int npasses
Definition: KSFoundation.h:1352
LOG_GRAD loggrd
STATUS scale(FLOAT(*inrotmat)[9], long(*outrotmat)[9], INT slquant, LOG_GRAD *lgrad, PHYS_GRAD *pgrad, INT contdebug)
int nslices
Definition: KSFoundation.h:1351
int ks_scan_getsliceloc(const KS_SLICE_PLAN *slice_plan, int passindx, int sltimeinpass)
Returns the spatially sorted slice index from a DATA_ACQ_ORDER struct array
Definition: KSFoundation_tgt.c:1023

◆ GEReq_predownload_store_sliceplan3D()

STATUS GEReq_predownload_store_sliceplan3D ( int  slices_in_slab,
int  slabs 
)

Sets mandatory global GE arrays for data acquisition (3D imaging)

The following global GE arrays are set based on slperpass (arg 1) and global op** variables:

  • data_acq_order[]: Critical for scanning
  • rsp_info[]: Copied from scan_info[] (the graphically prescibed slices), for conformance. Is a temporally sorted version of scan_info[] with integer rotation matrices. Not needed for scanning.
  • rsptrigger[]: Set to TRIG_INTERN for now.

data_acq_order[] is only available on HOST, why this function also copies data_acq_order[] to ks_data_acq_order[], which is an ipgexport array accessible on both HOST and TGT. This can be used by ks_scan_getsliceloc() to be independent on rsp_info[] during scan.

GEReq_predownload_store_sliceplan3D() has different input args compared to the 2D version. Here, a temporary slice plan is created based on slices_in_slab and slabs in order to create the proper content of data_acq_order[]. Note that it wouldn't have worked to pass ks_slice_plan for 3D. This is because we need a ks_slice_plan that is consistent with RF excitations for 2D, 3D, 3DMS in each sequence's looping structure in scan. For 3D, this very ks_slice_plan can then not also create the proper data_acq_order array here. This is why we pass in slices_in_slab and slabs instead and create e temp slice plan solely for the purpose of data_acq_order.

Parameters
[in]slices_in_slabNumber of slices in a slab
[in]slabsNumber slabs
Return values
STATUSSUCCESS or FAILURE
1123  {
1124  KS_SLICE_PLAN slice_plan;
1125 
1126  /* TODO: unclear for 3D MS, inteleaved and sequential */
1127  ks_calc_sliceplan_interleaved(&slice_plan, slices_in_slab * slabs, slices_in_slab, 1);
1128 
1129  return GEReq_predownload_store_sliceplan(slice_plan);
1130 
1131  }
STATUS GEReq_predownload_store_sliceplan(KS_SLICE_PLAN slice_plan)
Sets mandatory global GE arrays for data acquisition
Definition: GERequired.e:1001
Struct holding all information about slice locations and aquisition order
Definition: KSFoundation.h:1350
STATUS ks_calc_sliceplan_interleaved(KS_SLICE_PLAN *slice_plan, int nslices, int slperpass, int inpass_interleaves)
Calculates the data acquisition order for custom interleaved 2D scans using one or more passes...
Definition: KSFoundation_host.c:4872

◆ GEReq_predownload_setfilter()

STATUS GEReq_predownload_setfilter ( FILTER_INFO *  filt)

Assigns a global filter slot for a main sequence

This function must be called in predownload() after GE's initfilter() function, which resets all filter slots for scan and prescan entry points. The initfilter() function is called in GEReq_cvinit().

Given the FILTER_INFO of the acquisition window for the main pulse sequence (arg 1), this function assigns a new slot number (that matches one of the hardware slots in the data receive chain.

The .epfilter and .epprexres of GE's global struct array entry_point_table[] is also set.

Parameters
[in]filtPointer to FILTER_INFO struct (.filt field in KS_READ)
Return values
STATUSSUCCESS or FAILURE
1149  {
1150 
1151  setfilter(filt, SCAN);
1152 
1153  entry_point_table[L_SCAN].epfilter = (unsigned char) filt->fslot;
1154  entry_point_table[L_SCAN].epprexres = filt->outputs;
1155 
1156 
1157  /* APS2 & MPS2 */
1158  entry_point_table[L_APS2] = entry_point_table[L_MPS2] = entry_point_table[L_SCAN]; /* copy scan into APS2 & MPS2 */
1159  strcpy(entry_point_table[L_APS2].epname, "aps2");
1160  strcpy(entry_point_table[L_MPS2].epname, "mps2");
1161 
1162  return SUCCESS;
1163 
1164 } /* GEReq_predownload_setfilter() */

◆ GEReq_predownload_genVRGF()

STATUS GEReq_predownload_genVRGF ( const KS_READTRAP *const  readtrap)

Generates the vrgf.param file for rampsampling correction

When the .rampsampling field of a KS_READTRAP is set to 1, 1D gridding in the frequency encoding direction is necessary before FFT to obtain an equidistant k-space. GE's product reconstruction uses a file (vrgf.param) for this, which is generated by this function.

See also GEReq_predownload_setrecon_readphase(), which sets VRGF-specific global variables.

Parameters
[in]readtrap
Return values
STATUSSUCCESS or FAILURE
1182  {
1183  FILE *fpVRGF;
1184  float beta = 1.0;
1185  float alpha = 2.0 / (beta + 1.0);
1186 #ifdef SIM
1187  fpVRGF = fopen("./vrgf.param", "w");
1188 #else
1189  fpVRGF = fopen("/usr/g/bin/vrgf.param", "w");
1190 #endif
1191 
1192  /* based on: /ESE.../.../psdsupport/genVRGF.c */
1193 
1194  /* NOTE: The static file /usr/g/bin/vrgf.param2, i.e. with a trailing "2", containing the following
1195  must exist on the system in order for the executable /usr/g/bin/vrgf to generate vrgf.dat from
1196  the vrgf.param we are about to write:
1197  VRGFNORM= 1
1198  GAIN= 1.0
1199  VRGFWN= 1
1200  ALPHA= 0.46
1201  BETA= 1.0
1202  VRGFODS= 0.0
1203  VRGFCC= 0
1204  VRGFGS= 1
1205  VRGFSGG= 0
1206  VRGFBWF= -1.0
1207  */
1208 
1209 
1210  fprintf(fpVRGF, "VRGFIP= %d\n", readtrap->acq.filt.outputs);
1211  fprintf(fpVRGF, "VRGFOP= %d\n", readtrap->res);
1212  fprintf(fpVRGF, "PERIOD= %f\n", readtrap->acq.filt.tsp);
1213  fprintf(fpVRGF, "WAVE_CHOICE= %d\n", 1);
1214  fprintf(fpVRGF, "G1= %d\n", 1);
1215  fprintf(fpVRGF, "G2= %f\n", readtrap->grad.amp);
1216  fprintf(fpVRGF, "G3= %f\n", (readtrap->grad.plateautime / 2) / 1.0e6);
1217  fprintf(fpVRGF, "G4= %f\n", readtrap->grad.ramptime / 1.0e6);
1218  fprintf(fpVRGF, "G5= %f\n", alpha);
1219  fprintf(fpVRGF, "G6= %f\n", beta);
1220  fprintf(fpVRGF, "G7= %f\n", 0.0);
1221  fprintf(fpVRGF, "G8= %f\n", readtrap->acq.rbw * 1.0e3);
1222  fprintf(fpVRGF, "G9= %f\n", 0.0);
1223 
1224  if (fclose(fpVRGF) != 0) {
1225  ks_error("Can't close vrgf.param");
1226  }
1227 
1228  return SUCCESS;
1229 
1230 } /* GEReq_predownload_genVRGF() */
int plateautime
Definition: KSFoundation.h:584
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
float rbw
Definition: KSFoundation.h:734
KS_TRAP grad
Definition: KSFoundation.h:1586
int res
Definition: KSFoundation.h:1577
float amp
Definition: KSFoundation.h:581
FILTER_INFO filt
Definition: KSFoundation.h:735
KS_READ acq
Definition: KSFoundation.h:1574
int ramptime
Definition: KSFoundation.h:583

◆ GEReq_predownload_genrowflip()

STATUS GEReq_predownload_genrowflip ( KS_EPI epi,
int  blipsign,
int  assetflag,
int  dorowflip 
)

Generates the rowflip.param file for KS_EPI

GE's reconstruction (and data dumping) of EPI data (where every other readout is negative) needs to know which k-space lines that have been acquired with a negative gradient to perform a row flip on these lines before proceeding with Pfile writing and FFT processing.

Parameters
[in]epiPointer to KS_EPI
[in]blipsignKS_EPI_POSBLIPS or KS_EPI_NEGBLIPS
[in]assetflagFlag for ASSET mode or not (0: off, 2: ASSET_SCAN (on))
[in]dorowflipIf 0, write just ones to let rowflipping process for Pfiles being executed without actual flipping
Return values
STATUSSUCCESS or FAILURE
1249  {
1250  FILE *rowflipfp;
1251  int i = 0;
1252  int j = 0;
1253  int kyview = 0;
1254  int view1st, viewskip;
1255  int readsign = 1;
1256  int rowskip, res;
1257 #ifdef SIM
1258  rowflipfp = fopen("./rowflip.param", "w");
1259 #else
1260  rowflipfp = fopen("/usr/g/bin/rowflip.param", "w");
1261 #endif
1262 
1263  fprintf(rowflipfp, "# EPI recon control\n");
1264  fprintf(rowflipfp, "#\n");
1265  fprintf(rowflipfp, "# ky line number/flip operation\n");
1266  fprintf(rowflipfp, "%d %d\n", 0, 1);
1267 
1268  if (assetflag == ASSET_SCAN) {
1269  rowskip = 1;
1270  res = epi->blipphaser.res / epi->blipphaser.R;
1271  } else {
1272  rowskip = epi->blipphaser.R;
1273  res = epi->blipphaser.res;
1274  }
1275 
1276  for (i = 0; i < epi->etl; i++) {
1277  for (j = 0; j < rowskip; j++) {
1278  kyview = i * rowskip + j;
1279  readsign = (i % 2) ? -1 : 1;
1280  if (blipsign == KS_EPI_POSBLIPS && (epi->etl % 2 == 0)) {
1281  readsign *= -1;
1282  }
1283  fprintf(rowflipfp, "%d %d\n", kyview + 1, (dorowflip) ? readsign : 1);
1284  }
1285  }
1286  for (kyview = i * rowskip + j; kyview < res; kyview++)
1287  fprintf(rowflipfp, "%d %d\n", kyview + 1, 1);
1288 
1289  fprintf(rowflipfp, "#\n#\n#intleave 1stview skip gpol bpol gy1f rfpol tf nechoes init_echo_pol\n" );
1290 
1291  for (j = 0; j < rowskip; j++) {
1292  if (blipsign == KS_EPI_POSBLIPS && (epi->etl % 2 == 0)) {
1293  view1st = (assetflag == ASSET_SCAN) ? (epi->blipphaser.numlinestoacq - 1) : (epi->blipphaser.linetoacq[(epi->blipphaser.numlinestoacq - 1)] + j);
1294  viewskip = -rowskip;
1295  } else {
1296  view1st = (assetflag == ASSET_SCAN) ? 0 : (epi->blipphaser.linetoacq[0] + j);
1297  viewskip = rowskip;
1298  }
1299  fprintf(rowflipfp, "%d %d %d %d %d %d %d %d %d %d\n", j, view1st + 1, viewskip, 1, blipsign, 0 /* max int dephaser */, 1 /* rfpol*/, 0 /* tf */, epi->etl, 1);
1300  }
1301 
1302  fprintf(rowflipfp, "# esp (usec)\n");
1303  fprintf(rowflipfp, "%d \n", epi->read.grad.duration);
1304  fprintf(rowflipfp, "# tsp (usec)\n");
1305  fprintf(rowflipfp, "%f \n", epi->read.acq.filt.tsp);
1306  fprintf(rowflipfp, "# input samples\n");
1307  fprintf(rowflipfp, "%d \n", epi->read.acq.filt.outputs);
1308  fprintf(rowflipfp, "# readout amplitude (G/cm)\n");
1309  fprintf(rowflipfp, "%f \n", epi->read.grad.amp);
1310  fprintf(rowflipfp, "# Row FT size\n");
1311  fprintf(rowflipfp, "%d \n", epi->read.res);
1312  fprintf(rowflipfp, "# rhhnover \n");
1313  fprintf(rowflipfp, "%d \n", epi->blipphaser.nover);
1314  fprintf(rowflipfp, "# etl\n");
1315  fprintf(rowflipfp, "%d \n", epi->etl);
1316  fprintf(rowflipfp, "# number of interleaves\n");
1317  fprintf(rowflipfp, "%d \n", epi->blipphaser.R);
1318  fprintf(rowflipfp, "# low pass filter setting (kHz), or -1 for std. rcvr.\n");
1319  fprintf(rowflipfp, "%d \n", -1);
1320  fprintf(rowflipfp, "# total number of images\n");
1321  fprintf(rowflipfp, "%d \n", opslquant);
1322  fprintf(rowflipfp, "# end of file");
1323 
1324  fclose(rowflipfp);
1325 
1326  return SUCCESS;
1327 
1328 } /* GEReq_predownload_genrowflip() */
int R
Definition: KSFoundation.h:1680
int res
Definition: KSFoundation.h:1678
KS_PHASER blipphaser
Definition: KSFoundation.h:1840
int numlinestoacq
Definition: KSFoundation.h:1684
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1685
KS_TRAP grad
Definition: KSFoundation.h:1586
int etl
Definition: KSFoundation.h:1843
int res
Definition: KSFoundation.h:1577
KS_READTRAP read
Definition: KSFoundation.h:1837
Definition: KSFoundation.h:1929
float amp
Definition: KSFoundation.h:581
int nover
Definition: KSFoundation.h:1679
FILTER_INFO filt
Definition: KSFoundation.h:735
KS_READ acq
Definition: KSFoundation.h:1574
int duration
Definition: KSFoundation.h:585

◆ GEReq_predownload_setrecon_writekacq()

STATUS GEReq_predownload_setrecon_writekacq ( const KS_READTRAP *const  readtrap,
const KS_PHASER *const  phaser,
const KS_PHASER *const  zphaser 
)

Writes a kacq_yz.txt.***** file for use with GE's product ARC recon

If phaser.R > 1, a file is written to disk with phase encoding steps in an ARC accelerated scan ("kacq_yz.txt.*****"). This function has been adapted from GE's ARC.e, but supports only 2D (i.e. 1D-acceleration)

Parameters
[in]readtrapPointer to readout trapezoid. Used to determine k-space peak along kx
[in]phaserPointer to phase encoding object (KS_PHASER) with acceleration
[in]zphaserPointer to z phase encoding object (KS_PHASER) with acceleration. NULL for 2D
Return values
STATUSSUCCESS or FAILURE
1353  {
1354 
1355  FILE *fp;
1356  CHAR kacqFilename[BUFSIZ];
1357  int view;
1358  int arc_kx_peak_pos = 0; /* sample point units */
1359  /* int arc_ky_peak_pos = -1; */
1360  const CHAR kacqArcFilename[BUFSIZ] = "kacq_yz.txt";
1361  int num_echoes = 1; /* we don't understand what a value > 1 would mean. cf. ARC.e */
1362  int echo_index, slice;
1363  int numzencodes = (zphaser != NULL) ? zphaser->numlinestoacq : 1;
1364 
1365 #ifdef PSD_HW
1366  const CHAR kacqPath[BUFSIZ] = "/usr/g/psddata/";
1367  const CHAR kacqRawPath[BUFSIZ] = "/usr/g/mrraw/";
1368  sprintf(kacqFilename, "%s%s.%d", kacqPath, kacqArcFilename, rhkacq_uid);
1369 #else
1370  const CHAR kacqPath[BUFSIZ] = "./";
1371  const CHAR kacqRawPath[BUFSIZ] = "./";
1372  sprintf(kacqFilename, "%s%s", kacqPath, kacqArcFilename);
1373 #endif
1374 
1375  fp = fopen(kacqFilename, "w");
1376 
1377  /* position of k-space center in sample points along kx
1378  time2center - acqdelay is the time in [us] from start of acq window to the center of k-space
1379  acq.filt.tsp is the time in [us] for one sample point (with or without ramp sampling */
1380  arc_kx_peak_pos = (readtrap->time2center - readtrap->acqdelay) / readtrap->acq.filt.tsp;
1381 
1382  /* kacq header */
1383  fprintf(fp, "GE_KTACQ\t201\t0\n");
1384  fprintf(fp, "num_sampling_patterns\t%d\n", num_echoes);
1385  fprintf(fp, "num_mask_patterns\t%d\n", 0);
1386  fprintf(fp, "kx_peak_pos\t%d\n", arc_kx_peak_pos);
1387  /* fprintf(fp, "ky_peak_pos\t%d\n", arc_ky_peak_pos); */
1388  fprintf(fp, "---\n");
1389 
1390  /* Reconstruction schedule */
1391  fprintf(fp, "# Reconstruction schedule\n");
1392  fprintf(fp, "# t, Echo, Cal Table, Cal Pass, Accel Table, Accel Pass, Mask Table\n");
1393  fprintf(fp, "RECON_SCHEDULE\t%d\t%d\n", num_echoes, 7);
1394  fprintf(fp, "---\n");
1395  for (echo_index = 0; echo_index < num_echoes; echo_index++) {
1396  fprintf(fp,"%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 0, echo_index, -1, 0, echo_index, 0, -1);
1397  }
1398 
1399  /* Accelerated sampling pattern */
1400 for (echo_index = 0; echo_index < num_echoes; echo_index++) {
1401 
1402  fprintf(fp, "# Sampling Pattern 0 (Accel)\n");
1403  fprintf(fp, "# View Offset, Pass Offset, ky, kz\n");
1404 
1405  fprintf(fp, "SAMPLING_PATTERN\t%d\t%d\n", phaser->numlinestoacq * numzencodes, 4);
1406  fprintf(fp, "max_stride\t%d\t%d\n", phaser->R, (zphaser != NULL) ? zphaser->R : 1);
1407  int dimy;
1408  if (phaser->nover != 0)
1409  dimy = phaser->res / 2 + abs(phaser->nover); /* half nex */
1410  else
1411  dimy = phaser->res;
1412  fprintf(fp, "pattern_dimensions\t%d\t%d\n", dimy, (zphaser != NULL) ? exist(opslquant) : 1);
1413  fprintf(fp, "---\n");
1414  for (slice = 0; slice < numzencodes; slice++) {
1415  for (view = 0; view < phaser->numlinestoacq; view++) {
1416  if (zphaser != NULL)
1417  fprintf(fp, "%d\t%d\t%d\t%d\n", phaser->linetoacq[view] + 1 + (zphaser->linetoacq[view] * num_echoes + echo_index) * rhdayres, 0, phaser->linetoacq[view], zphaser->linetoacq[slice]);
1418  else
1419  fprintf(fp, "%d\t%d\t%d\t%d\n", phaser->linetoacq[view] + 1 + echo_index * rhdayres, 0, phaser->linetoacq[view], 0);
1420  }
1421  }
1422 
1423  } /* echo */
1424 
1425  fclose(fp);
1426 
1427  /* Automatically copy kacq file to a unique filename in
1428  /usr/g/mrraw if autolock is on */
1429  if (autolock == TRUE) {
1430  /* Copy file by reading to and writing from a buffer */
1431  CHAR kacqMrrawFilename[BUFSIZ];
1432  CHAR kacqRawFilename[BUFSIZ];
1433  FILE *srcFile = NULL;
1434  FILE *dstFile = NULL;
1435  size_t elemRead, elemWritten;
1436  size_t bufSz = 8192;
1437  char buf[8192];
1438 
1439  sprintf(kacqRawFilename, "%s.%d", kacqArcFilename, rhkacq_uid);
1440  sprintf(kacqMrrawFilename, "%s%s", kacqRawPath, kacqRawFilename);
1441 
1442  srcFile = fopen(kacqFilename, "rb");
1443  dstFile = fopen(kacqMrrawFilename, "wb");
1444 
1445  elemRead = bufSz;
1446  while (elemRead == bufSz) {
1447  elemRead = fread(buf, sizeof(char), bufSz, srcFile);
1448  elemWritten = fwrite(buf, sizeof(char), elemRead, dstFile);
1449  }
1450  (void) elemWritten;
1451 
1452  fclose(srcFile);
1453  fclose(dstFile);
1454 
1455  } /* autolock */
1456 
1457  return SUCCESS;
1458 
1459 } /* GEReq_predownload_setrecon_writekacq() */
int R
Definition: KSFoundation.h:1680
int res
Definition: KSFoundation.h:1678
int rhkacq_uid
int numlinestoacq
Definition: KSFoundation.h:1684
int linetoacq[KS_MAX_PHASEDYN]
Definition: KSFoundation.h:1685
int view
Definition: GERequired.e:2642
int nover
Definition: KSFoundation.h:1679
FILTER_INFO filt
Definition: KSFoundation.h:735
KS_READ acq
Definition: KSFoundation.h:1574
int time2center
Definition: KSFoundation.h:1585
int acqdelay
Definition: KSFoundation.h:1580

◆ GEReq_predownload_setrecon_accel()

STATUS GEReq_predownload_setrecon_accel ( const KS_READTRAP *const  readtrap,
const KS_PHASER *const  phaser,
const KS_PHASER *const  zphaser,
int  datadestination 
)

Sets rh*** variables related to parallel imaging acceleration

Parameters
[in]readtrapPointer to KS_READTRAP
[in]phaserPointer to KS_PHASER (phase)
[in]zphaserPointer to KS_PHASER (slice). NULL for 2D
[in]datadestinationValue to assign to rhexecctrl (c.f. epic.h)
Return values
STATUSSUCCESS or FAILURE
1475  {
1476  STATUS status;
1477 
1478  /* make sure we will be able to set all these CVs */
1479  _rhasset.fixedflag = FALSE;
1480  _rhasset_R.fixedflag = FALSE;
1481  _rhhnover.fixedflag = FALSE;
1482  _rhnframes.fixedflag = FALSE;
1483  _rhdayres.fixedflag = FALSE;
1484 
1485  if (phaser->R <= 1 && (zphaser == NULL || zphaser->R <= 1)) {
1486  rhasset = 0;
1487  rhasset_R = 1.0;
1488  rhassetsl_R = 1.0;
1489  return SUCCESS;
1490  }
1491 
1492  rhtype1 |= RHTYP1BAM0FILL; /* once more, just in case */
1493 
1494  if (datadestination & RHXC_XFER_IM) {
1495  /* if we are going to use GE recon (RHXC_XFER_IM = 8) */
1496 
1497  if (phaser->nacslines > 0) { /* ARC */
1498 
1499  /* ARC uses full BAM, i.e. stores the acquired lines at their proper locations in k-space with zero lines in between */
1500  rhhnover = abs(phaser->nover);
1501  rhnframes = phaser->numlinestoacq; /* # of acquired lines */
1502  rhdayres = (phaser->nover != 0) ? (phaser->res/2 + abs(phaser->nover) + 1) : (phaser->res + 1);
1503 
1504  rhasset = ACCEL_ARC; /* tell recon we are doing ARC only if we have ACS lines */
1505  status = GEReq_predownload_setrecon_writekacq(readtrap, phaser, zphaser);
1506  if (status != SUCCESS) return status;
1507 
1508  } else { /* ASSET */
1509 
1510  /* ASSET uses compressed BAM, i.e. stores only the acquired lines */
1511  rhhnover = abs(phaser->nover) / phaser->R;
1512  rhnframes = (phaser->nover != 0) ? (phaser->res / (2 * phaser->R)) : (phaser->res / phaser->R);
1513  rhdayres = rhnframes + rhhnover + 1;
1514 
1515  rhasset = ASSET_SCAN; /* if we don't have ACS lines, we will need to recon the data using some external calibration */
1516  }
1517 
1518  } else {
1519 
1520  /* store data as ARC (full BAM) */
1521  rhhnover = abs(phaser->nover);
1522  rhnframes = phaser->numlinestoacq; /* # of acquired lines */
1523  rhdayres = (phaser->nover != 0) ? (phaser->res / 2 + abs(phaser->nover) + 1) : (phaser->res + 1);
1524 
1525  rhasset = 0; /* we are going to do the reconstruction offline */
1526  }
1527 
1528  rhasset_R = 1.0 / phaser->R; /* inverse of acceleration factor */
1529  rhassetsl_R = (zphaser != NULL) ? (1.0 / zphaser->R) : 1;
1530 
1531  return SUCCESS;
1532 
1533 } /* GEReq_predownload_setrecon_accel() */
int R
Definition: KSFoundation.h:1680
int res
Definition: KSFoundation.h:1678
int nacslines
Definition: KSFoundation.h:1681
int numlinestoacq
Definition: KSFoundation.h:1684
int rhasset
STATUS GEReq_predownload_setrecon_writekacq(const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser)
Writes a kacq_yz.txt.***** file for use with GE&#39;s product ARC recon
Definition: GERequired.e:1353
int nover
Definition: KSFoundation.h:1679

◆ GEReq_predownload_setrecon_phase()

void GEReq_predownload_setrecon_phase ( const KS_PHASER *const  phaser,
const float  readfov,
const int  datadestination 
)
1537  {
1538  /* make sure we will be able to set all these CVs */
1539  _rhasset.fixedflag = FALSE;
1540  _rhasset_R.fixedflag = FALSE;
1541  _rhhnover.fixedflag = FALSE;
1542  _rhnframes.fixedflag = FALSE;
1543  _rhdayres.fixedflag = FALSE;
1544 
1545  if (phaser->nover != 0) { /* partial Fourier ky */
1546  rhnframes = phaser->res / 2;
1547  rhtype |= RHTYPFRACTNEX;
1548  } else {
1549  rhnframes = phaser->res;
1550  rhtype &= ~RHTYPFRACTNEX;
1551  }
1552 
1553  rhhnover = abs(phaser->nover);
1554  rhdayres = rhnframes + rhhnover + 1;
1555 
1556 
1557  rhexecctrl = datadestination;
1558  if (op3dgradwarp && !(rhexecctrl & RHXC_XFER_IM)) {
1559  /* 3D gradwarp requires at least one of the following bits set:
1560  #define RHXC_XFER_IM 0x0008 8 (GE online recon)
1561  #define RHXC_SAVE_IM 0x0010 16
1562  */
1563  (rhexecctrl) |= RHXC_SAVE_IM; /* parentheses around rhexecctrl prevents EPIC preprocessor to add fixedflag check */
1564  }
1565 
1566  rhphasescale = phaser->fov / readfov;
1567  if (phaser->R <= 1) {
1568  rhasset = 0;
1569  rhasset_R = 1.0;
1570  return;
1571  }
1572 
1573  rhtype1 |= RHTYP1BAM0FILL; /* once more, just in case */
1574 
1575  if (datadestination & RHXC_XFER_IM) {
1576  /* if we are going to use GE recon (RHXC_XFER_IM = 8) */
1577  if (phaser->nacslines > 0) { /* ARC */
1578  /* ARC uses full BAM, i.e. stores the acquired lines at their proper locations in k-space with zero lines in between */
1579  rhhnover = abs(phaser->nover);
1580  rhnframes = phaser->numlinestoacq; /* # of acquired lines */
1581  rhdayres = (phaser->nover != 0) ? (phaser->res/2 + abs(phaser->nover) + 1) : (phaser->res + 1);
1582  rhasset = ACCEL_ARC; /* tell recon we are doing ARC only if we have ACS lines */
1583  } else { /* ASSET */
1584  /* ASSET uses compressed BAM, i.e. stores only the acquired lines */
1585  rhhnover = abs(phaser->nover) / phaser->R;
1586  rhnframes = (phaser->nover != 0) ? (phaser->res / (2 * phaser->R)) : (phaser->res / phaser->R);
1587  rhdayres = rhnframes + rhhnover + 1;
1588  rhasset = ASSET_SCAN; /* if we don't have ACS lines, we will need to recon the data using some external calibration */
1589  }
1590  } else {
1591  /* store data as ARC (full BAM) */
1592  rhhnover = abs(phaser->nover);
1593  rhnframes = phaser->numlinestoacq; /* # of acquired lines */
1594  rhdayres = (phaser->nover != 0) ? (phaser->res / 2 + abs(phaser->nover) + 1) : (phaser->res + 1);
1595  rhasset = 0; /* we are going to do the reconstruction offline */
1596  }
1597 
1598  rhasset_R = 1.0 / phaser->R; /* inverse of acceleration factor */
1599 } /* GEReq_predownload_setrecon_phase() */
int R
Definition: KSFoundation.h:1680
int res
Definition: KSFoundation.h:1678
int nacslines
Definition: KSFoundation.h:1681
int numlinestoacq
Definition: KSFoundation.h:1684
int rhasset
int nover
Definition: KSFoundation.h:1679
float fov
Definition: KSFoundation.h:1677

◆ GEReq_predownload_setrecon_readwave()

void GEReq_predownload_setrecon_readwave ( const KS_READWAVE *const  readwave,
const int  yres,
const int  xres,
int  imsize_policy,
int  datadestination 
)
1603  {
1604  int max_xy;
1605 
1606  /* make sure we will be able to set all these CVs */
1607  _rhfrsize.fixedflag = FALSE;
1608  _rhdaxres.fixedflag = FALSE;
1609  _rhvrgf.fixedflag = FALSE;
1610  _rhvrgfxres.fixedflag = FALSE;
1611 
1612  /* raw data freq (x) size (works for both non-VRGF and VRGF) */
1613  rhfrsize = xres;
1614  rhdaxres = readwave->acq.filt.outputs;
1615 
1616 
1617  piforkvrgf = 0; /* 1 causes scan to spawn the vrgf process upon download */
1618  rhtype1 &= ~(RHTYP1FVRGF + RHTYP1PCORVRGF);
1619  rhuser32 = 0.0;
1620  rhuser33 = 0.0;
1621  rhuser34 = 0.0;
1622  rhuser35 = 0.0;
1623 
1624  /* image size */
1625  max_xy = IMax(2, xres, yres);
1626 
1627  rhmethod = 1; /* enable reduced image size, so we are in control */
1628  if (imsize_policy == KS_IMSIZE_MIN256) {
1629  max_xy = IMax(2, max_xy, 256);
1630  } else if (imsize_policy == KS_IMSIZE_POW2) {
1631  max_xy = ks_calc_nextpow2((unsigned int) max_xy); /* round up to nearest power of 2 if imsize_policy = KS_IMSIZE_POW2 */
1632  }
1633 
1634  /* recon image size with optional zerofilling */
1635  if (opzip512 && max_xy < 512) {
1636  max_xy = 512;
1637  } else if (opzip1024 && max_xy < 1024) {
1638  max_xy = 1024;
1639  }
1640  rhimsize = max_xy;
1641  rhrcxres = rhimsize;
1642  rhrcyres = rhimsize;
1643 
1644  /* freq. partial Fourier */
1645  if (abs(readwave->nover) > 0) {
1646  /* fractional echo (partial Fourier kx) */
1647  pitfeextra = rhdaxres * abs(readwave->nover) / (float)(readwave->res/2 + abs(readwave->nover));
1648  } else {
1649  pitfeextra = 0;
1650  }
1651  /* rhheover = pitfeextra; */
1652  rhfeextra = readwave->nover;
1653 
1654  /* chopping control */
1655  rhtype |= RHTYPCHP; /* ( |= 1) no chopping processing needed in recon */
1656 
1657  /* 3D recon flag */
1658  if(opimode == PSD_3D || opimode == PSD_3DM)
1659  rhtype |= RHTYP3D;
1660  else
1661  rhtype &= ~RHTYP3D;
1662 
1663 
1664 
1665 } /* GEReq_predownload_setrecon_readwave() */
Definition: KSFoundation.h:1948
Definition: KSFoundation.h:1948
FILTER_INFO filt
Definition: KSFoundation.h:735
unsigned int ks_calc_nextpow2(unsigned int x)
Gives the next higher 2^N for a given number
Definition: KSFoundation_host.c:4684
KS_READ acq
Definition: KSFoundation.h:1595
int res
Definition: KSFoundation.h:1600
int nover
Definition: KSFoundation.h:1602

◆ GEReq_predownload_setrecon_readphase()

void GEReq_predownload_setrecon_readphase ( const KS_READTRAP *const  readtrap,
const KS_PHASER *const  phaser,
const KS_PHASER *const  zphaser,
int  imsize_policy,
int  datadestination 
)

Sets required global rh*** variables for Cartsian imaging

For Cartesian pulse sequences, using one KS_READTRAP and one KS_PHASER (each of which may have multiple instances), the required rh*** variables are set based on the content of the sequence objects KS_READTRAP (arg 1) and KS_PHASER (arg 2). The fields in each sequence object, including e.g. partial Fourier and rampsampling, controls the setting of GE's rh*** variables. In addition, the third argument specifies the desired upsampling policy for small matrix sizes.

Parameters
[in]readtrapPointer to KS_READTRAP
[in]phaserPointer to KS_PHASER
[in]zphaserPointer to KS_PHASER (slice). NULL for 2D
[in]imsize_policyChoose between KS_IMSIZE_NATIVE, KS_IMSIZE_POW2, KS_IMSIZE_MIN256
[in]datadestinationValue for the rhexecctrl variable. Bitmasks for: KS_SAVEPFILES (dump Pfiles) and KS_GERECON (product recon)
Returns
void
1685  {
1686  int max_xy;
1687 
1688  /* make sure we will be able to set all these CVs */
1689  _rhfrsize.fixedflag = FALSE;
1690  _rhdaxres.fixedflag = FALSE;
1691  _rhdayres.fixedflag = FALSE;
1692  _rhnframes.fixedflag = FALSE;
1693  _rhhnover.fixedflag = FALSE;
1694  _rhvrgf.fixedflag = FALSE;
1695  _rhvrgfxres.fixedflag = FALSE;
1696  _rhasset.fixedflag = FALSE;
1697  _rhasset_R.fixedflag = FALSE;
1698 
1699  /* raw data freq (x) size (works for both non-VRGF and VRGF) */
1700  rhfrsize = readtrap->acq.filt.outputs;
1701  rhdaxres = readtrap->acq.filt.outputs;
1702 
1703  /* ramp sampling */
1704  rhvrgf = readtrap->rampsampling;
1705  rhvrgfxres = readtrap->res;
1706 
1707  if (readtrap->rampsampling) {
1708  piforkvrgf = 1; /* 1 causes scan to spawn the vrgf process upon download */
1709  rhtype1 |= (RHTYP1FVRGF + RHTYP1PCORVRGF); /* VRGF and VRGFafterPC */
1710 
1711  /* write vrgf.param */
1712  GEReq_predownload_genVRGF(readtrap);
1713 
1714  /* VRGF (rampsampling): Store shape of the read lobe to determine the k-space travel along kx (freq. dir.) for offline VRGF correction */
1715  rhuser32 = readtrap->acq.filt.tsp; /* time between sample points [often 2us] */
1716  rhuser33 = readtrap->grad.amp; /* Readout gradient amplitude */
1717  rhuser34 = (float) (readtrap->grad.plateautime / 2) / 1.0e6; /* half plateau time */
1718  rhuser35 = (float) (readtrap->grad.ramptime) / 1.0e6; /* attack/decay time */
1719  } else {
1720  piforkvrgf = 0; /* 1 causes scan to spawn the vrgf process upon download */
1721  rhtype1 &= ~(RHTYP1FVRGF + RHTYP1PCORVRGF);
1722  rhuser32 = 0.0;
1723  rhuser33 = 0.0;
1724  rhuser34 = 0.0;
1725  rhuser35 = 0.0;
1726  }
1727 
1728 
1729  /* image size */
1730  if (phaser != NULL) {
1731  max_xy = IMax(2, readtrap->res, phaser->res);
1732  } else {
1733  max_xy = readtrap->res;
1734  }
1735 
1736  rhmethod = 1; /* enable reduced image size, so we are in control */
1737  if (imsize_policy == KS_IMSIZE_MIN256) {
1738  max_xy = (max_xy > 256) ? 512 : 256; /* final image size is either 512 or 256 */
1739  } else if (imsize_policy == KS_IMSIZE_POW2) {
1740  max_xy = ks_calc_nextpow2((unsigned int) max_xy); /* round up to nearest power of 2 if imsize_policy = KS_IMSIZE_POW2 */
1741  }
1742 
1743  /* recon image size with optional zerofilling */
1744  if (opzip512 && max_xy < 512) {
1745  max_xy = 512;
1746  } else if (opzip1024 && max_xy < 1024) {
1747  max_xy = 1024;
1748  }
1749  rhimsize = max_xy;
1750  rhrcxres = rhimsize;
1751  rhrcyres = rhimsize;
1752 
1753  /* freq. partial Fourier */
1754  if (abs(readtrap->nover) > 0) {
1755  /* fractional echo (partial Fourier kx) */
1756  pitfeextra = rhfrsize - readtrap->res / 2;
1757  } else {
1758  pitfeextra = 0;
1759  }
1760  rhfeextra = pitfeextra;
1761 
1762  /* chopping control */
1763  rhtype |= RHTYPCHP; /* ( |= 1) no chopping processing needed in recon */
1764 
1765  /* 3D recon flag */
1766  if (KS_3D_SELECTED)
1767  rhtype |= RHTYP3D;
1768  else
1769  rhtype &= ~RHTYP3D;
1770 
1771  /* phase encoding (see also GEReq_predownload_setrecon_accel(), which may override these values) */
1772  if (phaser != NULL) {
1773  if (phaser->nover != 0) { /* partial Fourier ky */
1774  rhnframes = phaser->res / 2;
1775  rhtype |= RHTYPFRACTNEX;
1776  } else {
1777  rhnframes = phaser->res;
1778  rhtype &= ~RHTYPFRACTNEX;
1779  }
1780 
1781  rhhnover = abs(phaser->nover);
1782  rhdayres = rhnframes + rhhnover + 1;
1783 
1784  rhexecctrl = datadestination;
1785  if (op3dgradwarp && !(rhexecctrl & RHXC_XFER_IM)) {
1786  /* 3D gradwarp requires at least one of the following bits set:
1787  #define RHXC_XFER_IM 0x0008 8 (GE online recon)
1788  #define RHXC_SAVE_IM 0x0010 16
1789  */
1790  (rhexecctrl) |= RHXC_SAVE_IM; /* parentheses around rhexecctrl prevents EPIC preprocessor to add fixedflag check */
1791  }
1792 
1793  if (datadestination & RHXC_XFER_IM) {
1794  rhdacqctrl &= ~8192; /* enable GE's Orchestra Live recon */
1795  } else {
1796  rhdacqctrl |= 8192; /* disable GE's Orchestra Live recon */
1797  }
1798 
1799  /* Set up ARC/ASSET flags if R > 1 otherwise shut them off */
1800  GEReq_predownload_setrecon_accel(readtrap, phaser, zphaser, datadestination);
1801 
1802  rhphasescale = phaser->fov / readtrap->fov;
1803 
1804  } /* phaser != NULL */
1805 
1806 } /* GEReq_predownload_setrecon_readphase() */
int plateautime
Definition: KSFoundation.h:584
int res
Definition: KSFoundation.h:1678
Definition: KSFoundation.h:1948
float fov
Definition: KSFoundation.h:1576
Definition: KSFoundation.h:1948
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
KS_TRAP grad
Definition: KSFoundation.h:1586
STATUS GEReq_predownload_genVRGF(const KS_READTRAP *const readtrap)
Generates the vrgf.param file for rampsampling correction
Definition: GERequired.e:1182
int res
Definition: KSFoundation.h:1577
float amp
Definition: KSFoundation.h:581
int nover
Definition: KSFoundation.h:1679
FILTER_INFO filt
Definition: KSFoundation.h:735
unsigned int ks_calc_nextpow2(unsigned int x)
Gives the next higher 2^N for a given number
Definition: KSFoundation_host.c:4684
int nover
Definition: KSFoundation.h:1579
int rampsampling
Definition: KSFoundation.h:1578
KS_READ acq
Definition: KSFoundation.h:1574
float fov
Definition: KSFoundation.h:1677
int ramptime
Definition: KSFoundation.h:583
STATUS GEReq_predownload_setrecon_accel(const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser, int datadestination)
Sets rh*** variables related to parallel imaging acceleration
Definition: GERequired.e:1475

◆ GEReq_predownload_setrecon_annotations()

void GEReq_predownload_setrecon_annotations ( int  tsp,
int  readdur,
int  time2center,
int  echogap 
)

Sets ih*** variables for TE and rBW annotation

Uses the global UI CVs opnecho, opnex, opte and opte2

Parameters
[in]tspDwell time in [us], i.e. the duration of one sample (which is also 1/rBW)
[in]readdurDuration in [us] of the readout window
[in]time2centerTime in [us] to the center of the echo
[in]echogapGap between two echoes
Returns
void
1823  {
1824 
1825  int duration1, duration2;
1826  int echo_timeoffset2evenecho, echo_timeoffset2oddecho;
1827  int roundinglimit = 40ms;
1828 
1829  /* rBW annotation */
1830  ihvbw1 = 1.0e3 / (tsp * 2.0);
1831  ihvbw2 = ihvbw1;
1832  ihvbw3 = ihvbw1;
1833  ihvbw4 = ihvbw1;
1834  ihvbw5 = ihvbw1;
1835  ihvbw6 = ihvbw1;
1836  ihvbw7 = ihvbw1;
1837  ihvbw8 = ihvbw1;
1838  ihvbw9 = ihvbw1;
1839  ihvbw10 = ihvbw1;
1840  ihvbw11 = ihvbw1;
1841  ihvbw12 = ihvbw1;
1842  ihvbw13 = ihvbw1;
1843  ihvbw14 = ihvbw1;
1844  ihvbw15 = ihvbw1;
1845  ihvbw16 = ihvbw1;
1846 
1847  /* NEX annotation */
1848  ihnex = opnex;
1849 
1850  /* TE */
1851  ihte1 = (opte > roundinglimit) ? ks_calc_roundupms(opte) : opte;
1852 
1853  duration1 = (readdur - time2center) * 2 + echogap; /* 2x (time from k-space center to edge for 1st echo) + additional echo gap */
1854  duration2 = time2center * 2 + echogap; /* 2x (time from start to k-space center for 1st echo) + additional echo gap */
1855 
1856  if ((eeff == 1 && oeff == 0) || (eeff == 0 && oeff == 1) || (acq_type == TYPSPIN)) { /* alternating readout gradient polarity across echoes (like often in GRE), or SpinEcho */
1857  echo_timeoffset2evenecho = duration1; /* between 1 and 2, 3 and 4 etc. */
1858  echo_timeoffset2oddecho = duration2; /* between 2 and 3, 4 and 5 etc. */
1859  } else { /* same readout gradient polarity across echoes */
1860  /* we have a GRE sequence, and there are likely flyback gradients
1861  between each readout to allow for the readout gradient polarity to have the same sign for all echoes */
1862  echo_timeoffset2evenecho = readdur + echogap; /* between 1 and 2, 3 and 4 etc. */
1863  echo_timeoffset2oddecho = readdur + echogap; /* between 2 and 3, 4 and 5 etc. */
1864  }
1865 
1866  if (opnecho == 2) {
1867  if (pite2nub && existcv(opte2) && opte2 > 0) { /* use opte2 if the button is visible and it was selected */
1868  ihte2 = opte2;
1869  } else {
1870  /* partial Fourier note: 2nd readout will have its relative k-space center mirrored */
1871  ihte2 = opte + echo_timeoffset2evenecho;
1872  }
1873  } else if (opnecho > 2) {
1874  int pos = opte + echo_timeoffset2evenecho;
1875  ihte2 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1876  ihte3 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1877  ihte4 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1878  ihte5 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1879  ihte6 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1880  ihte7 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1881  ihte8 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1882  ihte9 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1883  ihte10 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1884  ihte11 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1885  ihte12 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1886  ihte13 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1887  ihte14 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1888  ihte15 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos; pos += echo_timeoffset2oddecho;
1889  ihte16 = (pos > roundinglimit) ? ks_calc_roundupms(pos) : pos;
1890  }
1891 
1892  /* rhte/rhte2 end up in the raw section of the rawdata header (rdb_hdr_te, rdb_hdr_te2)
1893  while opte/opte in the image section (te,te2). For opnecho > 2, the te2 field is sometimes 0, why
1894  we also need to rely on rdb_hdr_te2 for offline reconstruction */
1895  rhte = ihte1;
1896  rhte2 = ihte2;
1897 
1898 
1899  /* Flip Angle */
1900  ihflip = opflip;
1901 
1902 } /* GEReq_predownload_setrecon_annotations() */
int ks_calc_roundupms(int time)
Rounds up a value in [us] to nearest whole [ms]
Definition: KSFoundation_host.c:4696

◆ GEReq_predownload_setrecon_annotations_readtrap()

void GEReq_predownload_setrecon_annotations_readtrap ( KS_READTRAP readtrap,
int  echogap 
)

Sets ih*** variables for TE and rBW annotation based on a KS_READTRAP

This is a wrapper function to GEReq_predownload_setrecon_annotations() using a KS_READTRAP

Parameters
[in]readtrapPointer to KS_READTRAP
[in]echogapGap between two echoes
Returns
void
1917  {
1918 
1919  GEReq_predownload_setrecon_annotations(readtrap->acq.filt.tsp, readtrap->grad.duration, readtrap->time2center, echogap);
1920 
1921 } /* GEReq_predownload_setrecon_annotations_readtrap() */
void GEReq_predownload_setrecon_annotations(int tsp, int readdur, int time2center, int echogap)
Sets ih*** variables for TE and rBW annotation
Definition: GERequired.e:1823
KS_TRAP grad
Definition: KSFoundation.h:1586
FILTER_INFO filt
Definition: KSFoundation.h:735
KS_READ acq
Definition: KSFoundation.h:1574
int duration
Definition: KSFoundation.h:585
int time2center
Definition: KSFoundation.h:1585

◆ GEReq_predownload_setrecon_annotations_epi()

void GEReq_predownload_setrecon_annotations_epi ( KS_EPI epi,
int  echogap 
)

Sets ih*** variables for TE and rBW annotation based on a KS_EPI

This is a wrapper function to GEReq_predownload_setrecon_annotations() using a KS_EPI

Parameters
[in]epiPointer to KS_EPI
[in]echogapGap between two EPI trains
Returns
void
1936  {
1937  int maxtime_dephasers = IMax(2, epi->readphaser.duration, epi->blipphaser.grad.duration);
1938  int maxtime_rephasers = IMax(2, epi->readphaser.duration, epi->blipphaser.grad.duration);
1939  int halfkspace_duration = ((epi->read.grad.duration + epi->read_spacing) * epi->etl / 2) - epi->read_spacing / 2;
1940  /* time for extra lines beyond half-kspace for partial Fourier in ky */
1941  int overscan_duration = ((epi->read.grad.duration + epi->read_spacing) * (epi->blipphaser.nover / epi->blipphaser.R)) - epi->read_spacing / 2;
1942  int epiduration, time2center;
1943 
1944  if (opautote == PSD_MINTE) {
1945  epiduration = (maxtime_dephasers + overscan_duration + halfkspace_duration + maxtime_rephasers);
1946  time2center = maxtime_dephasers + overscan_duration;
1947  } else {
1948  epiduration = (maxtime_dephasers + 2 * halfkspace_duration + maxtime_rephasers);
1949  time2center = maxtime_dephasers + halfkspace_duration;
1950  }
1951  GEReq_predownload_setrecon_annotations(epi->read.acq.filt.tsp, epiduration, time2center, echogap);
1952 
1953 
1954 } /* GEReq_predownload_setrecon_annotations_epi() */
int R
Definition: KSFoundation.h:1680
KS_TRAP grad
Definition: KSFoundation.h:1676
void GEReq_predownload_setrecon_annotations(int tsp, int readdur, int time2center, int echogap)
Sets ih*** variables for TE and rBW annotation
Definition: GERequired.e:1823
KS_PHASER blipphaser
Definition: KSFoundation.h:1840
KS_TRAP grad
Definition: KSFoundation.h:1586
int etl
Definition: KSFoundation.h:1843
KS_READTRAP read
Definition: KSFoundation.h:1837
int nover
Definition: KSFoundation.h:1679
KS_TRAP readphaser
Definition: KSFoundation.h:1838
FILTER_INFO filt
Definition: KSFoundation.h:735
int read_spacing
Definition: KSFoundation.h:1844
KS_READ acq
Definition: KSFoundation.h:1574
int duration
Definition: KSFoundation.h:585

◆ GEReq_predownload_setrecon_voldata()

void GEReq_predownload_setrecon_voldata ( int  numvols,
const KS_SLICE_PLAN  slice_plan 
)

Sets rh*** variables related to multi-volume imaging

The combination of rh*** variables allow for 50,000 image planes in GE's database.

However, Pfile data stops writing after 512 planes. To store more than 512 image planes as rawdata, RDS (Raw Data Server) or multivolume Pfiles can be used instead. It is possible that other mechanisms will be available through GE's upcoming Orchestra Live in the future.

Parameters
[in]numvolsNumber of volumes (opfphases)
[in]slice_planThe slice plan (KS_SLICE_PLAN), set up using ks_calc_sliceplan() or similar
Returns
void
1973  {
1974  int numechoes;
1975 
1976  if (numvols < 1)
1977  numvols = 1;
1978 
1979  /* GE's CVs for #slices/TR and #passes (acqs) */
1980  _slquant1.fixedflag = 0;
1981  _acqs.fixedflag = 0;
1982  slquant1 = slice_plan.nslices_per_pass;
1983  acqs = slice_plan.npasses;
1984  /* prescan */
1985  picalmode = 0;
1986  pislquant = slquant1;
1987 
1988  /* rhscnframe and rhpasframe are used when scanning in auto-pass mode w/o specific pass-packets (like GEendpass).
1989  To enable auto-pass mode, set rhtype1 |= RHTYP1AUTOPASS and set these variables to the proper value.
1990  It is unclear how this would work with partial Fourier and ARC, and has not been tested. */
1991  rhscnframe = 0 /* rhnslices*ceil(opnex)*rhdayres */;
1992  rhpasframe = 0 /* slquant1*ceil(opnex)*rhdayres */;
1993  rhtype1 &= ~RHTYP1AUTOPASS; /* diable auto-pass. I.e. require the use of pass packets (which is standard anyway) in scan to dump Pfiles */
1994 
1995  /* raw size */
1996  numechoes = IMax(2, rhnecho, opnecho);
1997  if (!KS_3D_SELECTED) {
1998  rhrawsize = slquant1 * numechoes * (2 * rhptsize) * rhdaxres * rhdayres;
1999  } else {
2000  rhrawsize = opslquant * numechoes * (2 * rhptsize) * rhdaxres * rhdayres;
2001  }
2002 
2003  {
2004  char tmpstr[100];
2005  sprintf(tmpstr, "rhrawsize = %d bytes/channel (KSFoundation)", (int) rhrawsize);
2006  cvdesc(rhrawsizeview, tmpstr);
2007  }
2008 
2009  /* Volumes & total size */
2010  rhnphases = numvols; /* must be = numvols (not numvols*acqs=#pfiles !!)
2011  - if 1 when numvols >1:
2012  Prep Action failed: error please try again. ErrorLog="The integer value for ps_to_rs[0] in the header = 0 "
2013  - if numvols*acqs when acqs > 1 and numvols == 1:
2014  Scan failed (after few secs, no images) */
2015  rhnpasses = rhnphases * slice_plan.npasses; /* must be == # volumes (Pfiles) dumped or system hangs and needs rebooting ! */
2016  rhreps = rhnphases;
2017  if (!KS_3D_SELECTED) {
2018  rhnslices = slice_plan.nslices * rhnphases;
2019  } else {
2020  rhnslices = opslquant * opvquant * rhnphases;
2021  }
2022  rhmphasetype = 0; /* Interleaved multiphase */
2023 
2024  rhtype1 |= RHTYP1BAM0FILL ; /* zerofill BAM for clean Pfiles */
2025  rhformat &= ~RHF_ZCHOP; /* no z chopping by default */
2026  rhformat |= RHF_SINGLE_PHASE_INFO;
2027 
2028  /* Gradwarp Mode */
2029  rhuser47 = cfgradcoil;
2030 
2031  /* copy useful variables to raw header for recon */
2032  /* rhuser32-35 are reserved for off-line VRGF correction (Karolinska) */
2033  rhuser48 = pitscan; /* scan time */
2034 
2035 } /* GEReq_predownload_setrecon_voldata() */
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int nslices_per_pass
Definition: KSFoundation.h:1353
int npasses
Definition: KSFoundation.h:1352
int nslices
Definition: KSFoundation.h:1351

◆ GEReq_predownload_setrecon_epi()

STATUS GEReq_predownload_setrecon_epi ( KS_EPI epi,
int  numvols2store,
const KS_SLICE_PLAN  slice_plan,
int  echogap,
int  blipsign,
int  datadestination,
int  multishotflag,
int  staticghostcal,
int  imsize_policy 
)

Wrapper function that set up rh*** variable for a KS_EPI object using other functions

Calls GEReq_predownload_setrecon_readphase(), GEReq_predownload_setrecon_voldata() and GEReq_predownload_setrecon_annotations_epi(), and GEReq_predownload_genrowflip(). Additionally, some rh*** variables are overridden for EPI.

Parameters
[in]epiPointer to KS_EPI
[in]numvols2storeNumber of volumes to store (including calibration vols such as ghostcorr)
[in]slice_planThe slice plan (KS_SLICE_PLAN) set up using ks_slice_plan() or similar
[in]echogapGap between two EPI trains in [us]
[in]blipsignKS_EPI_POSBLIPS or KS_EPI_NEGBLIPS
[in]datadestinationValue passed on to GEReq_predownload_setrecon_readphase() to set rhexecctrl
[in]multishotflag0: Parallel imaging mode 1: Multishot mode
[in]staticghostcalIntegrated refscan (Nyquist ghost correction). 0:Off, 1:On
[in]imsize_policyChoice between KS_IMSIZE_NATIVE, KS_IMSIZE_POW2, KS_IMSIZE_MIN256
Return values
STATUSSUCCESS or FAILURE
2059  {
2060 
2061  if (datadestination & RHXC_XFER_IM) {
2062  return ks_error("%s: Online recon not supported for KS_EPI data on DV26 or later", __FUNCTION__);
2063  }
2064 
2065  GEReq_predownload_setrecon_readphase(&epi->read, &epi->blipphaser, NULL, imsize_policy, datadestination); /* also sets rhasset when R > 1 */
2066  GEReq_predownload_setrecon_voldata(numvols2store, slice_plan); /* opfphases = number of volumes */
2068 
2069 
2070  /* EPI specific rh* vars */
2071  rhileaves = epi->blipphaser.R;
2072  rhkydir = (blipsign == KS_EPI_POSBLIPS) ? 2 : 0;
2073  rhmphasetype = 0; /* Interleaved multiphase */
2074 
2075  if (multishotflag > 0) {
2076  /* .R for multi-shot. Override values set in GEReq_predownload_setrecon_readphase()->GEReq_predownload_setrecon_accel() */
2077  _rhasset.fixedflag = FALSE;
2078  _rhasset_R.fixedflag = FALSE;
2079  rhasset = 0;
2080  rhasset_R = 1.0;
2081  }
2082 
2083  /* Turn on row-flipping if ETL > 1 */
2084  if (epi->etl > 1) {
2085  rhformat |= RHF_USE_FLIPTABLE;
2086  if (datadestination & RHXC_XFER_IM) {
2087  /* Online recon: Single-shot w/ or w/o ASSET */
2088  GEReq_predownload_genrowflip(epi, blipsign, rhasset, TRUE);
2089  } else {
2090  /* Offline recon, say we do rowflip in rhformat, because otherwise GERecon('EPI.ComputeCoefficients') does not
2091  work (requires RHF_USE_FLIPTABLE to be set).
2092  But let's not set any negative entries in the file for offline use to avoid rowflipping to actually occur:
2093  DV26+: This file is ignored for scan archives
2094  Pre DV26: We don't want the rows to be flipped correctly in the Pfile currently since we don't understand
2095  why the lines are flipped wrong for mulitshot EPI. We deal with rowflipping ourselves in the recon
2096  */
2097  GEReq_predownload_genrowflip(epi, blipsign, rhasset, FALSE);
2098  }
2099  } else {
2100  rhformat &= ~RHF_USE_FLIPTABLE;
2101  }
2102 
2103  /* fermi filter */
2104  rhfermr = opxres/2;
2105 
2106 
2107  /* override flip control set in GEReq_predownload()->{@inline loadrheader.e rheaderinit}
2108  N.B.: ks_scan_epi_loadecho() changes the view indices based on the blipsign argument. Hence,
2109  there is no need to inform recon that k-space data should be flipped (as opposed to the product
2110  epi.e/epi2.e, which use oepf = 1 when pepolar = 1) */
2111  eepf = 0;
2112  eeff = 0;
2113  oepf = 0;
2114  oeff = 0;
2115  set_echo_flip(&rhdacqctrl, &chksum_rhdacqctrl, eepf, oepf, eeff, oeff); /* clear bit 1 - flips image in phase dir */
2116 
2117  rhdacqctrl |= 8192; /* disable Orchestra recon */
2118 
2119  /* save echo spacing value into rhesp */
2120  rhesp = epi->read.grad.duration;
2121 
2122 
2123 
2124  /* default but see below */
2125  rhpctemporal = 1;
2126  rhpccoil = 0;
2127  rhref = (staticghostcal) ? 5 : 0;
2128 
2129  /* Diffusion or not */
2130  if (opdiffuse || optensor) {
2131  rhtype1 |= RHTYP1DIFFUSIONEPI;
2132  } else {
2133  rhtype1 &= ~RHTYP1DIFFUSIONEPI;
2134  }
2135 
2136 
2137 
2138  return SUCCESS;
2139 
2140 } /* GEReq_predownload_setrecon_epi() */
int R
Definition: KSFoundation.h:1680
int opxres
void GEReq_predownload_setrecon_readphase(const KS_READTRAP *const readtrap, const KS_PHASER *const phaser, const KS_PHASER *const zphaser, int imsize_policy, int datadestination)
Sets required global rh*** variables for Cartsian imaging
Definition: GERequired.e:1685
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KS_PHASER blipphaser
Definition: KSFoundation.h:1840
STATUS GEReq_predownload_genrowflip(KS_EPI *epi, int blipsign, int assetflag, int dorowflip)
Generates the rowflip.param file for KS_EPI
Definition: GERequired.e:1249
KS_TRAP grad
Definition: KSFoundation.h:1586
int etl
Definition: KSFoundation.h:1843
void GEReq_predownload_setrecon_annotations_epi(KS_EPI *epi, int echogap)
Sets ih*** variables for TE and rBW annotation based on a KS_EPI
Definition: GERequired.e:1936
KS_READTRAP read
Definition: KSFoundation.h:1837
int rhasset
void GEReq_predownload_setrecon_voldata(int numvols, const KS_SLICE_PLAN slice_plan)
Sets rh*** variables related to multi-volume imaging
Definition: GERequired.e:1973
Definition: KSFoundation.h:1929
int duration
Definition: KSFoundation.h:585

◆ GEReq_predownload_prescan_options()

STATUS GEReq_predownload_prescan_options ( RG_CAL_MODE_E  rg_cal_mode)

Prescan options

Parameters
[in]dorecvgainFALSE (0): Use fixed R1=5. TRUE (1): Use R1 from Prescan->APS2()
Return values
STATUSSUCCESS or FAILURE
2151  {
2152 
2153  /* cvoverride(psd_pscall, -1, PSD_FIX_ON, PSD_EXIST_ON); */ /* disable all prescan? */
2154 
2155  /* Transmit Gain (TG) Auto always */
2156  cvoverride(psd_psctg, 0, PSD_FIX_ON, PSD_EXIST_ON); /* 0: Auto TG */
2157  pidotg = psd_psctg;
2158 
2159 
2160 #if EPIC_RELEASE > 26
2161  /* Gradient shim. Stop sequence specific overrides from Prescan.e so Shim menu reflects what is going
2162  to happen, regardless of EPI/diffusion modes */
2163  opgradshim = 2; /* Grad Shim (Auto). Default, will be changed by Shim menu */
2164  if (opgradshim == 2) { /* Auto */
2165  cvoverride(psd_pscshim, 0, PSD_FIX_ON, PSD_EXIST_ON);
2166  } else if (opgradshim == 1) { /* Force ON */
2167  cvoverride(psd_pscshim, 1, PSD_FIX_ON, PSD_EXIST_ON);
2168  } else if (opgradshim == 0) { /* Force OFF */
2169  cvoverride(psd_pscshim, -1, PSD_FIX_ON, PSD_EXIST_ON);
2170  }
2171  pidoshim = psd_pscshim;
2172 #endif
2173 
2174  /* Receive gain (R1/R2) control:
2175  epic_ui_control.h:
2176  typedef enum RG_CAL_MODE {
2177  RG_CAL_MODE_MIN = 0,
2178  RG_CAL_MODE_MEASURED = 0,
2179  RG_CAL_MODE_HIGH_FIXED = 1,
2180  RG_CAL_MODE_LOW_FIXED = 2,
2181  RG_CAL_MODE_AUTO = 3,
2182  RG_CAL_MODE_MAX = 3
2183  } RG_CAL_MODE_E;
2184  */
2185  cvoverride(oprgcalmode, rg_cal_mode, PSD_FIX_ON, PSD_EXIST_ON);
2186 
2187  return SUCCESS;
2188 
2189 }

◆ GEReq_cvinit()

STATUS GEReq_cvinit ( void  )

Helper function to be called at the beginning of cvinit()

In the beginning of cvinit() the following lines should be added:

STATUS status = GEReq_cvinit();
if (status != SUCCESS) return status;

This function sets up various global GE stuff, including e.g. the gradient specs. The gradient specs are controlled by ks_srfact and ks_qfact. ks_srfact Should have a value that will allow scanning on all MR systems without PNS effects. Also, ks_srfact does not affect the EPI train in ksepi.e, since it controls the slewrate and gradient max separately. ks_qfact is supposed to be 1 by default, with the purpose to from an optimal setting reduce the slewrate to reduce the acoustic noise. A default value of 1.0 will make the system perform best but with high acoustic noise. A value of about 8-10 may be a good trade-off between acoustic noise reduction and reasonable image quality.

In this function, ks_sarcheckdone is set to FALSE. This CV is checked in GEReq_predownload() and ks_pg_rf(), which both will complain if it is not has been set to TRUE. GEReq_eval_checkTR_SAR_calcs() sets this CV to TRUE.

It is important that an error returned from GEReq_cvinit() also results in an error in cvinit(), otherwise it will not show up in the UI.

Return values
STATUSSUCCESS or FAILURE
2220  {
2221 
2222  /* ART: Acoustic noise reduction
2223  Imaging option button "Acoustic reduction":
2224  - PSD_IOPT_MILDNOTE in sequence_iopts[]
2225  - Sets CV opsilent = TRUE
2226  When acoustic noise reduction (ART) imaging option is checked, enable the ART tab in the UI too
2227  by forcing cfnumartlevels = 2
2228  - "Moderate" radio button on ART tab: CV opsilentlevel = 1
2229  - "High" radio button on ART tab: CV opsilentlevel = 2
2230  */
2231  cvoverride(cfnumartlevels, 2, PSD_FIX_OFF, PSD_EXIST_ON);
2232  pinumartlevels = cfnumartlevels;
2233 
2234  if (opsilent) {
2235  _ks_qfact.existflag = TRUE;
2236  if (opsilentlevel == 1) {
2237  /* moderate */
2238  ks_qfact = 8.0;
2239  } else {
2240  /* high */
2241  ks_qfact = 20.0;
2242  }
2243  } else {
2244  ks_qfact = 1.0;
2245  }
2246 
2247 
2248  {
2249  }
2250 
2251  EpicConf();
2252 
2253  /* set gradient limitations (calling GEs obloptimize() & further ramptime modifications) */
2255 
2256  /* resets all filter #. From this point, ok to call setfilter() */
2257  initfilter();
2258 
2259  /* setsysparams() sets psd_grd_wait and psd_rf_wait for the system */
2260  setsysparms();
2261 #ifdef SIM
2262  /* In simulation, we don't want them to confuse the timing in WTools */
2263  _psd_grd_wait.fixedflag = 0;
2264  _psd_rf_wait.fixedflag = 0;
2265  psd_grd_wait = 0;
2266  psd_rf_wait = 0;
2267 #endif
2268 
2269 
2270  /* GE CVs that could use a wider min/max range: */
2271  cvmax(rhfrsize, 32768);
2272  cvmax(rhdaxres, 32768);
2273  cvmax(opphasefov, 5); /* to allow larger FOV in phase enc dir that freq */
2274  cvmax(rhnslices, 50000); /* 50,000, which is 5x of RHF_MAX_IMAGES_MULTIPHASE = 10000 */
2275  cvmax(rhreps, 2048); /* max 2048 vols */
2276  cvmax(rhnphases, 2048); /* max 2048 vols */
2277  cvmax(opfphases, 2048); /* max 2048 vols */
2278  cvmax(opyres, 1024); /* max 1024 yres */
2279  cvmax(opslthick, 200); /* max 200 mm slice thickness */
2280  cvmax(optr, 60s); /* max 60s TR */
2281  cvmax(ihtr, 60s);
2282  cvmax(rhref, 5); /* Allow 1st-volume ghost correction as GE's diffusion EPI (only works for single shot) */
2283  cvmax(opbval, 30000);
2284  cvmax(opileave, 1);
2285 
2286  /* activate Advisory panel */
2287  piadvise = PSD_ON;
2288  piadvmin = (1 << PSD_ADVTE); /* TE Advisory on */
2289  piadvmin |= (1 << PSD_ADVTR); /* TR Advisory on */
2290  piadvmin |= (1 << PSD_ADVRCVBW);/* rBW Advisory on */
2291  piadvmin |= (1 << PSD_ADVFOV);/* FOV Advisory on */
2292  piadvmax = piadvmin;
2293 
2294  {
2295  }
2296 
2297 
2298  /* KSFoundation indicator variable for completed SAR checks (c.f. GEReq_eval_checkTR_SAR_calcs(), which sets it to TRUE) */
2299  ks_sarcheckdone = FALSE;
2300 
2301  /* GE's psd_name seems not be available on TGT, to let's copy this one */
2302 #if EPIC_RELEASE >= 27
2303 /* Since RX27R02, GE's psd_name no longer exists */
2304 {
2305  strcpy(ks_psdname, get_psd_name());
2306 }
2307 #else
2308  strcpy(ks_psdname, psd_name);
2309 #endif
2310 
2311 
2312  return SUCCESS;
2313 
2314 } /* GEReq_cvinit() */
int opyres
STATUS GEReq_init_gradspecs(LOG_GRAD *loggrd, PHYS_GRAD *phygrd, float srfact)
Initialize logical and physical gradient specifications
Definition: GERequired.e:393
PHYS_GRAD phygrd
char ks_psdname[256]
Definition: GERequired.e:221
float ks_qfact
Definition: GERequired.e:243
LOG_GRAD loggrd
int ks_sarcheckdone
Definition: GERequired.e:219
int psd_grd_wait
int psd_rf_wait
float opslthick
float ks_srfact
Definition: GERequired.e:242

◆ GEReq_cveval()

STATUS GEReq_cveval ( void  )

Helper function to be called at the beginning of cveval()

In the beginning of cveval() the following lines should be added:

STATUS status = GEReq_cveval();
if (status != SUCCESS) return status;

This function up various global GE stuff, and copies also the struct array scan_info, holding the prescribed slice locations to ks_scan_info, the latter which can also be accessible on TGT.

Simulation (WTools): If we have ks_simscan = 1 (default), simscan() will have make up slice locations in ks_scan_info based on opslthick, opslspace and opslquant. Note, GE clears scan_info between cvcheck() and predownload() when in simulation. Hence, we now have the opposite case, i.e. we have some slice info data in ks_scan_info but nothing in scan_info.

It is important that an error returned from GEReq_cveval() also results in an error in cveval(), otherwise it will not show up in the UI.

Return values
STATUSSUCCESS or FAILURE
2342  {
2343 
2344  {
2345  }
2346 
2347  InitAdvPnlCVs();
2348 
2349 #ifdef PSD_HW
2350  /* MR scanner (hardware): copy scan_info to ks_scan_info, so we can use this data on TGT */
2351  memcpy(ks_scan_info, scan_info, opslquant*sizeof(SCAN_INFO));
2352 #else
2353  /* WTools (sim) */
2354  if (ks_simscan)
2355  simscan();
2356 #endif
2357 
2358  return SUCCESS;
2359 
2360 } /* GEReq_cveval() */
STATUS simscan(void)
Simulate scan locations in simulation (WTools)
Definition: GERequired.e:299
int ks_simscan
Definition: GERequired.e:241
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ getAPxParam()

void getAPxParam ( optval *  min,
optval *  max,
optdelta *  delta,
optfix *  fix,
float  coverage,
int  algorithm 
)

Mandatory APx functions for PSDs from DV26

DV26 requires getAPxAlgorithm() and getAPxParam() functions to exist in each PSD. Empty getAPxAlgorithm() and getAPxParam() functions are declared below in GERequired.e to allow compilation on DV26. If a PSD wants to use this new functionality in DV26 it should add the following line: #define KS_PSD_USE_APX 1 in its section, so that KS_PSD_USE_APX is not set to 0 here, and hence getAPxAlgorithm() and getAPxParam() wont be redeclared here in GERequired.e.

2381  {
2382  /* Need to be filled when APx is supported in this PSD */
2383 }

◆ getAPxAlgorithm()

int getAPxAlgorithm ( optparam *  optflag,
int *  algorithm 
)
2385  {
2386  return APX_CORE_NONE;
2387 }

◆ GEReq_cvcheck()

STATUS GEReq_cvcheck ( void  )

Helper function to be called at the beginning of cvcheck()

In the beginning of cvcheck() the following lines should be added:

STATUS status = GEReq_cveval();
if (status != SUCCESS) return status;

It is important that an error returned from GEReq_cvcheck() also results in an error in cvcheck(), otherwise it will not show up in the UI.

Return values
STATUSSUCCESS or FAILURE
2407  {
2408 
2409  if (existcv(optr) && optr < avmintr) {
2410  epic_error(use_ermes, "The minimum TR is %-d ms", EM_PSD_TR_OUT_OF_RANGE, EE_ARGS(1), INT_ARG, (avmintr / 1ms));
2411  return ADVISORY_FAILURE;
2412  }
2413  if (existcv(optr) && optr > avmaxtr) {
2414  epic_error(use_ermes, "The maximum TR is %-d ms", EM_PSD_TR_OUT_OF_RANGE, EE_ARGS(1), INT_ARG, (avmaxtr / 1ms));
2415  return ADVISORY_FAILURE;
2416  }
2417  if ((exist(opte) < avminte) && existcv(opte)) {
2418  epic_error(use_ermes, "The minimum TE is %-d ms", EM_PSD_TE_OUT_OF_RANGE1, 1, INT_ARG, (avminte / 1ms));
2419  return ADVISORY_FAILURE;
2420  }
2421  if ((exist(opte) > avmaxte) && existcv(opte)) {
2422  epic_error(use_ermes, "The maximum TE is %-d ms", EM_PSD_TE_OUT_OF_RANGE1, 1, INT_ARG, (avmaxte / 1ms));
2423  return ADVISORY_FAILURE;
2424  }
2425 
2426  return SUCCESS;
2427 
2428 } /* GEReq_cvcheck() */

◆ GEReq_predownload()

STATUS GEReq_predownload ( void  )

Helper function to be called at the beginning of predownload()

In the beginning of predownload() the following lines should be added:

STATUS status = GEReq_predownload();
if (status != SUCCESS) return status;

This function up various global GE stuff related to recon and data filters. Also, ks_sarcheckdone is checked to make sure that GEReq_eval_checkTR_SAR_calcs() has been called to monitor SAR/heating limits.

It is important that an error returned from GEReq_predownload() also results in an error in predownload(), otherwise it will not show up in the UI.

Return values
STATUSSUCCESS or FAILURE
2451  {
2452 
2453  {
2454  }
2455 
2456  nex = ceil(opnex); /* nex is used in rheaderinit instead of opnex, so must set it here. otherwise prescan fails */
2457 
2458  /* UsePgenOnHost() (Imakefile) likes calling calcPulseParams() at this spot, containing "predownload.in" */
2459  calcPulseParams(0);
2460 
2461  {
2462  }
2463 
2464  /* Set rhkacq_uid for ARC support and linking plots */
2465  int uid;
2466  struct tm now;
2467  time_t now_epoch = time(NULL);
2468  /* Generate unique ID for this scan for naming kacq files and
2469  debug files. Use the current date and time (MMDDHHMMSS).
2470  Cannot include the year because this is larger than a
2471  signed 32-bit integer */
2472  localtime_r(&now_epoch, &now);
2473  uid = now.tm_sec +
2474  now.tm_min * 100 +
2475  now.tm_hour * 10000 +
2476  now.tm_mday * 1000000 +
2477  (now.tm_mon + 1) * 100000000;
2478  rhkacq_uid = uid;
2479 
2480 
2481  /* Check that SAR calculations have been performed */
2482  if (ks_sarcheckdone != TRUE) {
2483 #ifdef SIM
2484  if (existcv(optr) == TRUE && existcv(opte) == TRUE && existcv(opslquant) == TRUE) {
2485  /* In simulation (WTools), predownload is called every time a CV is changed but
2486  ks_sarcheckdone will not be set to TRUE in GEReq_eval_checkTR_SAR_calcs() unless
2487  optr, opte and opslquant have all been set (existcv() != FALSE). Hence, in simulation,
2488  we cannot throw an error before these have been set */
2489  return ks_error("%s: Missing call to GEReq_eval_checkTR_SAR()", __FUNCTION__);
2490  }
2491 #else
2492  return ks_error("%s: Missing call to GEReq_eval_checkTR_SAR()", __FUNCTION__);
2493 #endif
2494  }
2495 
2496  return SUCCESS;
2497 
2498 } /* GEReq_predownload() */
int rhkacq_uid
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
STATUS calcPulseParams(int p)
Mandatory GE function. Includes predownload.in
Definition: GERequired.e:283
int ks_sarcheckdone
Definition: GERequired.e:219

◆ GEReq_pulsegenBegin()

void GEReq_pulsegenBegin ( void  )

Helper function to be called at the beginning of pulsegen()

In the beginning of pulsegen() the following lines should be added:

This function up various global GE stuff related to pulsegen()

2527  {
2528 
2529  sspinit(psd_board_type);
2530 
2531  {
2532  }
2533 } /* GEReq_pulsegenBegin() */

◆ GEReq_pulsegenEnd()

void GEReq_pulsegenEnd ( void  )

Helper function to be called at the end of pulsegen()

In the end of pulsegen(), but before buildinstr(), the following lines should be added:

This function up prescan pulsegen and adds a PASSPACK sequence ("GEendpass"), which is used to dump rawdata and mark the end of scan. See GEReq_endofpass() and GEReq_endofscan() and how they are used in a psd.

2551  {
2552 
2553 #ifdef IPG
2554  {
2555  }
2556 
2557 /* pass sequence to dump Pfiles */
2558 PASSPACK(GEendpass, pw_passpacket-1ms);
2559 SEQLENGTH(GEpass, pw_passpacket, GEpass);
2560 
2561 #endif
2562 } /* GEReq_pulsegenEnd() */
int pw_passpacket
Definition: GERequired.e:238

◆ GEReq_endofpass()

int GEReq_endofpass ( )

Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction

After calling this function, the parent function must switch back to the previous/main sequence using ks_scan_playsequence() (or boffset()).

2574  {
2575 #ifdef IPG
2576  boffset(off_GEpass);
2577  setwamp(SSPD + DABPASS, &GEendpass, 2 ); /* end of pass */
2578  startseq(0, (short) MAY_PAUSE);
2579 #endif
2580  return pw_passpacket;
2581 } /* GEReq_endofpass() */
STATUS startseq(s16, s16)
STATUS boffset(long *offsets)
int pw_passpacket
Definition: GERequired.e:238

◆ GEReq_endofscan()

int GEReq_endofscan ( )

Sets SSP word in sequence off_GEpass() to tell system that scan is done

2590  {
2591 #ifdef IPG
2592  boffset(off_GEpass);
2593  setwamp(SSPD + DABSCAN, &GEendpass, 2 ); /* end of scan */
2594  startseq(0, (short) MAY_PAUSE);
2595 #endif
2596  return pw_passpacket;
2597 } /* GEReq_endofscan() */
STATUS startseq(s16, s16)
STATUS boffset(long *offsets)
int pw_passpacket
Definition: GERequired.e:238

◆ GEReq_endofpassandscan()

int GEReq_endofpassandscan ( )

Sets SSP word in sequence off_GEpass() to tell system that scan is done

2606  {
2607  #ifdef IPG
2608  boffset(off_GEpass);
2609  setwamp(SSPD + DABPASS + DABSCAN, &GEendpass, 2 ); /* end of scan */
2610  startseq(0, (short) MAY_PAUSE);
2611  #endif
2612  return pw_passpacket;
2613  } /* GEReq_endofscan() */
STATUS startseq(s16, s16)
STATUS boffset(long *offsets)
int pw_passpacket
Definition: GERequired.e:238

◆ dummylinks()

void dummylinks ( void  )

Not sure what this function does, but it exists in all product psds.

2672  {
2673  epic_loadcvs( "thefile" ); /* for downloading CVs */
2674 }

◆ GEReq_initRSP()

void GEReq_initRSP ( void  )

RSP Init. To be inserted in the psdinit() function (or scan()) in the main sequence

2683  {
2684 
2685  /* Initialize everything to a known state */
2686  setrfconfig((short) ks_rfconf); /* ENBL_RHO1 + ENBL_THETA + ENBL_OMEGA + ENBL_OMEGA_FREQ_XTR1 = 141 */
2687  rspqueueinit(200); /* Initialize to 200 entries */
2688  syncoff(&GEpass); /* Deactivate sync during pass */
2689 }
int ks_rfconf
Definition: GERequired.e:240

Variable Documentation

◆ rfpulseInfo

RF_PULSE_INFO rfpulseInfo[RF_FREE] = { {0, 0} }

◆ avail_image_time

int avail_image_time

◆ act_tr

ifndef ACT_TR_EXISTS int act_tr

◆ ks_scan_info

endif SCAN_INFO ks_scan_info[SLTAB_MAX] = {DEFAULT_AXIAL_SCAN_INFO}

◆ ks_slice_plan

◆ ks_sarcheckdone

int ks_sarcheckdone = FALSE

◆ ks_psdname

char ks_psdname[256]

◆ ks_perform_slicetimeplot

int ks_perform_slicetimeplot = FALSE

◆ obl_debug

int obl_debug = 0 with {0, 1, 0, INVIS, "On(=1) to print messages for obloptimize",}

◆ obl_method

int obl_method = PSD_OBL_OPTIMAL with {PSD_OBL_RESTRICT, PSD_OBL_OPTIMAL, PSD_OBL_OPTIMAL, INVIS, "On(=1) to optimize the targets based on actual rotation matrices",}

◆ filter_echo1

int filter_echo1 = 0 with {, , , INVIS, "Scan filter slot number needed for prescan",}

◆ pw_passpacket

int pw_passpacket = 50ms with {10ms, 1000ms, 50ms, VIS, "Duration of the passpacket sequence",}

◆ ks_rfconf

int ks_rfconf = ENBL_RHO1 + ENBL_THETA + ENBL_OMEGA + ENBL_OMEGA_FREQ_XTR1

◆ ks_simscan

int ks_simscan = 1 with {0, 1, 1, VIS, "Simulate slice locations if 1 (and in simulation)",}

◆ ks_srfact

float ks_srfact = 1.0 with {0.01, 3.0, 1.0, VIS, "Slewrate factor (low value = slower gradients)",}

◆ ks_qfact

float ks_qfact = 1.0 with {0.1, 40.0, 1.0, VIS, "Quietness factor",}

◆ ks_gheatfact

float ks_gheatfact = 1.0 with {0.0, 1.0, 1.0, VIS, "Degree of honoring gradient heating calculations (0:ignore, 1:fully obey)"}

◆ ks_plot_filefmt

int ks_plot_filefmt = KS_PLOT_MAKEPNG with {KS_PLOT_OFF,KS_PLOT_MAKEPNG,KS_PLOT_MAKEPNG, VIS, "Plot format 0:off 1:PDF 2:SVG 3:PNG"}

◆ ks_plot_kstmp

int ks_plot_kstmp = FALSE with {FALSE,TRUE,FALSE, VIS, "0: off 1:Copy plots to mrraw/kstmp"}

◆ ks_clinicalmode

int ks_clinicalmode = CLINICAL_MODE with {0, 1, CLINICAL_MODE, VIS, "Clinical mode: on=1 / off=0"}

◆ maxB1

float maxB1[MAX_ENTRY_POINTS]

◆ maxB1Seq

float maxB1Seq

◆ debugstate

short debugstate

◆ viewtable

short viewtable[513]

◆ psdexitarg

PSD_EXIT_ARG psdexitarg

◆ rspent

int rspent

◆ rspdda

int rspdda

◆ rspbas

int rspbas

◆ rspvus

int rspvus

◆ rspgy1

int rspgy1

◆ rspasl

int rspasl

◆ rspesl

int rspesl

◆ rspchp

int rspchp

◆ rspnex

int rspnex

◆ rspslq

int rspslq

◆ rspsct

int rspsct

◆ rsprep

int rsprep

◆ chopamp

short chopamp

◆ seqCount

int seqCount

◆ view

int view

◆ excitation

int excitation

◆ debug

int debug

◆ entry_name_list

const CHAR* entry_name_list[ENTRY_POINT_MAX]
Initial value:
= {
"scan",
"mps2",
"aps2",
}