KSFoundation  [April-2021]
A platform for simpler EPIC programming on GE MR systems
ksfse: FSE sequence (2D/3D)

Data Structures

struct  KSFSE_SEQUENCE
 

Macros

#define KSFSE_MINHNOVER   6
 
#define KSFSE_MIN_SSI_TIME   200
 
#define KSFSE_MAXTHICKFACT   3.0
 
#define KSFSE_INIT_SEQUENCE   {KS_INIT_SEQ_CONTROL, KS_INIT_READTRAP, KS_INIT_TRAP, KS_INIT_PHASER, KS_INIT_PHASER, KS_INIT_TRAP, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_PHASEENCODING_PLAN};
 

Enumerations

enum  { KSFSE_RECOVERY_OFF, KSFSE_RECOVERY_T1WOPT, KSFSE_RECOVERY_FAST }
 

Functions

STATUS cvinit (void)
 
STATUS cveval (void)
 
STATUS my_cveval (void)
 
STATUS cvcheck (void)
 
STATUS predownload (void)
 
STATUS pulsegen (void)
 
STATUS mps2 (void)
 
STATUS aps2 (void)
 
STATUS scan (void)
 
 abstract ("FSE [KSFoundation]")
 
 psdname ("ksfse")
 
void ksfse_eval_TEmenu (int esp, int maxte, int etl, double optechono)
 
STATUS ksfse_calc_echo (double *bestecho, double *optecho, KS_PHASER *pe, int TE, int etl, int esp)
 
STATUS ksfse_pg (int start_time)
 
int ksfse_scan_coreslice (const SCAN_INFO *slice_pos, int dabslice, int shot, int exc)
 
int ksfse_scan_coreslice_nargs (const SCAN_INFO *slice_pos, int dabslice, int nargs, void **args)
 
int ksfse_scan_sliceloop (int slperpass, int passindx, int shot, int exc)
 
int ksfse_scan_sliceloop_nargs (int slperpass, int nargs, void **args)
 
float ksfse_scan_acqloop (int passindx)
 
float ksfse_scan_scanloop ()
 
STATUS ksfse_scan_seqstate (SCAN_INFO slice_info, int shot)
 
void ksfse_init_imagingoptions (void)
 
STATUS ksfse_init_UI (void)
 
STATUS ksfse_eval_UI ()
 
int ksfse_eval_esp (int *min90_180, int *min180_echo, int slicecheck, KSFSE_SEQUENCE *seq)
 
int ksfse_eval_optimalkxnover (KSFSE_SEQUENCE *seq)
 
float ksfse_eval_rfstretchfactor (float patientweight, float flipangle, int tailoredrf_flag)
 
STATUS ksfse_eval_setuprfpulses_2D (KSFSE_SEQUENCE *seq)
 
STATUS ksfse_eval_setuprfpulses_3D (KSFSE_SEQUENCE *seq)
 
STATUS ksfse_eval_setuprfpulses_recovery (KSFSE_SEQUENCE *seq)
 
int ksfse_eval_ssitime ()
 
STATUS ksfse_eval_setupobjects ()
 
STATUS ksfse_eval_TErange ()
 
STATUS ksfse_eval_inversion (KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksfse_eval_tr (KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksfse_eval_scantime ()
 
STATUS ksfse_check ()
 
STATUS ksfse_predownload_plot (KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksfse_predownload_setrecon ()
 
STATUS ksfse_etlphaseamps (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_PHASER *phaser, KS_PHASER *zphaser, int shot)
 
void ksfse_spoilamp (KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_TRAP *spoiler, int res, int shot)
 
void ksfse_scan_rf_off ()
 
void ksfse_scan_rf_on ()
 
STATUS ksfse_scan_init (void)
 
STATUS ksfse_scan_prescanloop (int nloops, int dda)
 

Variables

KS_SEQ_COLLECTION seqcollection
 
float ksfse_excthickness = 0
 
float ksfse_gscalerfexc = 0.9
 
float ksfse_flipexc = 90.0 with {0.0, 180.0, 90.0, VIS, "Excitation flip angle [deg]",}
 
float ksfse_spoilerarea = 2000.0 with {0.0, 20000.0, 5000.0, VIS, "ksfse spoiler gradient area",}
 
float rf_stretch_rfexc = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF excitation pulse if > 1.0",}
 
int ksfse_inflowsuppression = 0 with {0, 1, 0, VIS, "In-flow Suppression [0:OFF, 1:ON]",}
 
float ksfse_inflowsuppression_mm = 0.0 with {0.0, 100.0, 0.0, VIS, "In-flow suppression [mm]",}
 
int ksfse_vfa = 1 with {0, 1, 1, VIS, "Variable flip angles [0:OFF, 1:ON]",}
 
float ksfse_crusherscale = 0.5 with {0.0, 20.0, 0.5, VIS, "scaling of crusher gradient area",}
 
float ksfse_gscalerfref = 0.9
 
int ksfse_slicecheck = 0 with {0, 1, 0, VIS, "move readout to z axis for slice thickness test",}
 
float rf_stretch_rfref = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF refocusing pulses if > 1.0",}
 
float rf_stretch_all = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch all RF pulses if > 1.0",}
 
int ksfse_recovery = KSFSE_RECOVERY_OFF with {KSFSE_RECOVERY_OFF, KSFSE_RECOVERY_FAST, KSFSE_RECOVERY_OFF, VIS, "Recovery. 0:off 1:T1wopt 2:T2fast", }
 
float rf_stretch_rfrecovery = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF recovery pulses if > 1.0",}
 
int ksfse_kxnover_min = KSFSE_MINHNOVER with {KSFSE_MINHNOVER, 512, KSFSE_MINHNOVER, VIS, "Min mum kx overscans for minTE",}
 
int ksfse_kxnover = 32 with {KSFSE_MINHNOVER, 512, 32, VIS, "Num kx overscans for minTE",}
 
int ksfse_rampsampling = 0 with {0, 1, 0, VIS, "Rampsampling [0:OFF 1:ON]",}
 
int ksfse_extragap = 0 with {0, 100ms, 0, VIS, "extra gap between readout [us]",}
 
int ksfse_etlte = 1 with {0, 1, 1, VIS, "ETL controls TE",}
 
float ksfse_xcrusherarea = 100.0 with {0.0, 1000.0, 100.0, VIS, "x crusher area for readout",}
 
int ksfse_esp = 0 with {0, 1000000, 0, VIS, "View-only: Echo spacing in [us]",}
 
int ksfse_noph = 0 with {0, 1, 0, VIS, "Turn OFF phase encoding [0:Disabled 1:Enabled]",}
 
int ksfse_minacslines = 12 with {0, 512, 12, VIS, "Minimum ACS lines for ARC",}
 
int ksfse_minzacslines = 12 with {0, 512, 12, VIS, "Minimum z ACS lines for ARC",}
 
int ksfse_pos_start = KS_RFSSP_PRETIME with {0, , KS_RFSSP_PRETIME, VIS, "us from start until the first waveform begins",}
 
int ksfse_ssi_time = KSFSE_MIN_SSI_TIME with {50, , KSFSE_MIN_SSI_TIME, VIS, "time from eos to ssi in intern trig",}
 
int ksfse_dda = 2 with {0, 200, 2, VIS, "Number of dummy scans for steady state",}
 
int ksfse_debug = 1 with {0, 100, 1, VIS, "Write out e.g. plot files (unless scan on HW)",}
 
int ksfse_imsize = KS_IMSIZE_NATIVE with {KS_IMSIZE_NATIVE, KS_IMSIZE_MIN256, KS_IMSIZE_MIN256, VIS, "img. upsamp. [0:native 1:pow2 2:min256]"}
 
int ksfse_abort_on_kserror = FALSE with {0, 1, 0, VIS, "Hard program abort on ks_error [0:OFF 1:ON]",}
 
int ksfse_mintr = 0 with {0, 20s, 0, VIS, "Min TR (ms) [0: Disabled]",}
 
int ksfse_maxtr = 0 with {0, 40s, 0, VIS, "Max TR (ms) [0: Disabled]",}
 
KSFSE_SEQUENCE ksfse = KSFSE_INIT_SEQUENCE
 
int sequence_iopts []
 
int volindx
 
int passindx
 

Detailed Description

MR-contrasts supported

Features

Macro Definition Documentation

◆ KSFSE_MINHNOVER

#define KSFSE_MINHNOVER   6

◆ KSFSE_MIN_SSI_TIME

#define KSFSE_MIN_SSI_TIME   200

◆ KSFSE_MAXTHICKFACT

#define KSFSE_MAXTHICKFACT   3.0

◆ KSFSE_INIT_SEQUENCE

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
KSFSE_RECOVERY_OFF 
KSFSE_RECOVERY_T1WOPT 
KSFSE_RECOVERY_FAST 
Definition: ksfse_implementation.e:41
Definition: ksfse_implementation.e:41
Definition: ksfse_implementation.e:41

Function Documentation

◆ cvinit()

STATUS cvinit ( void  )
84  {
85  STATUS status;
86 
87  status = GEReq_cvinit();
88  if (status != SUCCESS) return status;
89 
90  /* reset debug file ./ks_debug.txt (SIM) or /usr/g/mrraw/ks_debug.txt (HW) */
91  ks_dbg_reset();
92 
93  /* Imaging Options buttons */
95 
96  /* Inversion UI init */
97  status = ksinv_init_UI();
98  if (status != SUCCESS) return status;
99 
100  /* Setup UI buttons */
101  status = ksfse_init_UI();
102  if (status != SUCCESS) return status;
103 
104  return SUCCESS;
105 
106 } /* cvinit() */
STATUS ksinv_init_UI()
Initializes inversion related UI
Definition: KSInversion.e:839
void ksfse_init_imagingoptions(void)
Initial handling of imaging options buttons and top-level CVs at the PSD type-in pages
Definition: ksfse_implementation.e:226
STATUS ksfse_init_UI(void)
Initial setup of user interface (UI) with default values for menus and fields
Definition: ksfse_implementation.e:284
void ks_dbg_reset()
Clear debug file content
Definition: KSFoundation_common.c:119
STATUS GEReq_cvinit(void)
Helper function to be called at the beginning of cvinit()
Definition: GERequired.e:2220

◆ cveval()

STATUS cveval ( void  )
114  {
115  /*
116  cveval() is called 37+ times per UI button push on the MR system, while cvcheck() is only called once.
117  For a faster execution we have a my_cveval() function that is called in cvcheck() instead
118  */
119 
120  return SUCCESS;
121 }

◆ my_cveval()

STATUS my_cveval ( void  )
124  {
125  STATUS status;
126 
128 
129  status = GEReq_cveval();
130  if (status != SUCCESS) return status;
131 
132  /* User Interface updates & opuserCV sync */
133  status = ksfse_eval_UI();
134  if (status != SUCCESS) return status;
135 
136  /* Setup sequence objects */
137  status = ksfse_eval_setupobjects();
138  if (status != SUCCESS) return status;
139 
140  /* Calculate minimum (and maximum TE), and sometimes ETL */
141  status = ksfse_eval_TErange();
142  if (status != SUCCESS) return status;
143 
144  /* Run the sequence once (and only once after ksfse_eval_setupobjects()) in cveval() to
145  get the sequence duration and the number of object instances (for grad/rf limits in GEReq...limits()) */
146  status = ksfse_pg(ksfse_pos_start);
147  if (status != SUCCESS) return status;
148 
150  if (status != SUCCESS) return status;
151 
152 
153  /*--------- Begin: Additional sequence modules -----------*/
154 
155  /* Spatial Sat */
156  status = ksspsat_eval(&seqcollection);
157  if (status != SUCCESS) return status;
158 
159  /* ChemSat */
160  status = kschemsat_eval(&seqcollection);
161  if (status != SUCCESS) return status;
162 
163  /* Inversion (general & FSE specific). Must be the last sequence module added */
164  if (!KS_3D_SELECTED) {
166  if (status != SUCCESS) return status;
167  }
168  /*--------- End: Additional sequence modules -----------*/
169 
170 
171  /* Min TR, #slices per TR (unless Inversion on), RF/gradient heating & SAR */
172  status = ksfse_eval_tr(&seqcollection);
173  if (status != SUCCESS) return status;
174 
175  /* RF scaling across sequence modules */
177  if (status != SUCCESS) return status;
178 
179  /* scan time */
180  status = ksfse_eval_scantime();
181  if (status != SUCCESS) return status;
182 
183  return SUCCESS;
184 
185 } /* my_cveval() */
STATUS ksspsat_eval(KS_SEQ_COLLECTION *seqcollection)
Spatial Sat evaluation function, to be called from the cveval() function of the main sequence...
Definition: KSSpSat.e:633
KS_SEQ_COLLECTION seqcollection
Definition: ksfse.e:78
STATUS kschemsat_eval(KS_SEQ_COLLECTION *seqcollection)
Chemsat evaluation function, to be called from the cveval() function of the main sequence
Definition: KSChemSat.e:273
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
STATUS ks_eval_addtoseqcollection(KS_SEQ_COLLECTION *seqcollection, KS_SEQ_CONTROL *seqctrl) WARN_UNUSED_RESULT
Adds a sequence module (KS_SEQ_CONTROL) to the KS_SEQ_COLLECTION struct for later RF scaling and SAR ...
Definition: KSFoundation_host.c:149
STATUS ksfse_eval_TErange()
Sets the min/max TE and echo spacing for the FSE train based on rBW, res and ETL
Definition: ksfse_implementation.e:1500
STATUS ksfse_eval_scantime()
Set the number of dummy scans for the sequence and calls ksfse_scan_scanloop() to determinethe length...
Definition: ksfse_implementation.e:1792
STATUS ksfse_eval_UI()
Gets the current UI and checks for valid inputs
Definition: ksfse_implementation.e:678
STATUS ksfse_eval_inversion(KS_SEQ_COLLECTION *seqcollection)
Wrapper function to KSInversion functions to add single and dual IR support to this sequence...
Definition: ksfse_implementation.e:1646
STATUS ksfse_eval_tr(KS_SEQ_COLLECTION *seqcollection)
Evaluation of number of slices / TR, set up of slice plan, TR validation and SAR checks
Definition: ksfse_implementation.e:1730
int ksfse_pos_start
Definition: ksfse_implementation.e:125
void ks_init_seqcollection(KS_SEQ_COLLECTION *seqcollection)
Resets KS_SEQ_COLLECTION to its default value (KS_INIT_SEQ_COLLECTION)
Definition: KSFoundation_host.c:117
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
STATUS ksfse_eval_setupobjects()
Sets up all sequence objects for the main sequence module (KSFSE_SEQUENCE ksfse)
Definition: ksfse_implementation.e:1352
STATUS ksfse_pg(int)
The ksfse (main) pulse sequence
Definition: ksfse_implementation.e:2102
STATUS GEReq_cveval(void)
Helper function to be called at the beginning of cveval()
Definition: GERequired.e:2342
STATUS GEReq_eval_rfscaling(KS_SEQ_COLLECTION *seqcollection)
Performs RF scaling of all RF pulses in the KS_SEQ_COLLECTION and Prescan
Definition: GERequired.e:758

◆ cvcheck()

STATUS cvcheck ( void  )
193  {
194  STATUS status;
195 
196  status = my_cveval();
197  if (status != SUCCESS) return status;
198 
199  status = GEReq_cvcheck();
200  if (status != SUCCESS) return status;
201 
202  status = ksfse_check();
203  if (status != SUCCESS) return status;
204 
205  status = ksinv_check();
206  if (status != SUCCESS) return status;
207 
209 
210  return SUCCESS;
211 
212 } /* cvcheck() */
STATUS GEReq_cvcheck(void)
Helper function to be called at the beginning of cvcheck()
Definition: GERequired.e:2407
STATUS ksfse_check()
Returns error of various parameter combinations that are not allowed for ksfse
Definition: ksfse_implementation.e:1827
int abort_on_kserror
Definition: KSFoundation_common.c:40
int ksfse_abort_on_kserror
Definition: ksfse_implementation.e:130
STATUS my_cveval(void)
Definition: ksfse.e:124
STATUS ksinv_check()
Checks related to inversion
Definition: KSInversion.e:1879

◆ predownload()

STATUS predownload ( void  )
218  {
219  STATUS status;
220 
221  status = GEReq_predownload();
222  if (status != SUCCESS) return status;
223 
224  /* Set filter slot # for SCAN, APS2, MPS2 */
226 
227  /* slice ordering */
228  /* The following GE globals must be set appropriately:
229  data_acq_order[], rsp_info[], rsprot[], rsptrigger[]. This is a must for a main pulse sequence */
230  if (KS_3D_SELECTED) {
231  status = GEReq_predownload_store_sliceplan3D(opslquant, opvquant);
232  } else {
234  }
235  if (status != SUCCESS) return status;
236 
237  /* generic rh-vars setup */
239  ksfse_imsize, KS_SAVEPFILES * autolock + KS_GERECON * (rhrecon < 1000) /* online recon if rhrecon < 1000 */);
241  GEReq_predownload_setrecon_voldata(opfphases, ks_slice_plan); /* opfphases = number of volumes */
242 
243  /* KSInversion predownload */
244  status = ksinv_predownload_setrecon();
245  if (status != SUCCESS) return status;
246 
247  /* further sequence specific recon settings that have not been set correctly at this point */
248  status = ksfse_predownload_setrecon();
249  if (status != SUCCESS) return status;
250 
251  /* plotting of sequence modules and slice timing to disk */
253 
254 
255  return SUCCESS;
256 
257 } /* predownload() */
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 GEReq_predownload_setfilter(FILTER_INFO *filt)
Assigns a global filter slot for a main sequence
Definition: GERequired.e:1149
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
STATUS GEReq_predownload_store_sliceplan(KS_SLICE_PLAN slice_plan)
Sets mandatory global GE arrays for data acquisition
Definition: GERequired.e:1001
KS_SEQ_COLLECTION seqcollection
Definition: ksfse.e:78
STATUS ksfse_predownload_plot(KS_SEQ_COLLECTION *seqcollection)
Plotting of sequence modules and slice timing to PNG/SVG/PDF files
Definition: ksfse_implementation.e:1890
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_GERECON
Definition: KSFoundation.h:176
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
KS_READTRAP read
Definition: ksfse_implementation.e:51
STATUS ksfse_predownload_setrecon()
Last-resort function to override certain recon variables not set up correctly already
Definition: ksfse_implementation.e:1964
STATUS ksinv_predownload_setrecon()
Sets IR-related recon variables in predownload
Definition: KSInversion.e:1898
int ksfse_imsize
Definition: ksfse_implementation.e:129
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
int ksfse_extragap
Definition: ksfse_implementation.e:110
#define KS_SAVEPFILES
Definition: KSFoundation.h:175
STATUS GEReq_predownload_store_sliceplan3D(int slices_in_slab, int slabs)
Sets mandatory global GE arrays for data acquisition (3D imaging)
Definition: GERequired.e:1123
FILTER_INFO filt
Definition: KSFoundation.h:735
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
KS_READ acq
Definition: KSFoundation.h:1574
void GEReq_predownload_setrecon_annotations_readtrap(KS_READTRAP *readtrap, int echogap)
Sets ih*** variables for TE and rBW annotation based on a KS_READTRAP
Definition: GERequired.e:1917
STATUS GEReq_predownload(void)
Helper function to be called at the beginning of predownload()
Definition: GERequired.e:2451

◆ pulsegen()

STATUS pulsegen ( void  )
265  {
266 
268 
269  /* Main sequence */
271  KS_SEQLENGTH(seqcore, ksfse.seqctrl);
272 
273  /* Spatial Sat */
275 
276  /* ChemSat sequence module */
278  KS_SEQLENGTH(seqKSChemSat, kschemsat.seqctrl); /* does nothing if kschemsat.seqctrl.duration = 0 */
279 
280  /* Inversion sequence modules */
281  ksinv_pulsegen();
282 
284 
285  buildinstr(); /* load the sequencer memory */
286 
287  return SUCCESS;
288 
289 } /* pulsegen() */
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
int kschemsat_pg(KSCHEMSAT_SEQUENCE *chemsat)
The kschemsat (fatsat) pulse sequence module
Definition: KSChemSat.e:320
KS_SEQLENGTH(seq_name, seq_struct)
Creates a hardware sequence for the current sequence module
Definition: GERequired.e:65
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
void ksinv_pulsegen()
Generation of all inversion-related sequence modules
Definition: KSInversion.e:2077
void GEReq_pulsegenEnd(void)
Helper function to be called at the end of pulsegen()
Definition: GERequired.e:2551
int ksfse_pos_start
Definition: ksfse_implementation.e:125
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
STATUS ksspsat_pulsegen()
Definition: KSSpSat.e:754
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71
STATUS ksfse_pg(int)
The ksfse (main) pulse sequence
Definition: ksfse_implementation.e:2102
void GEReq_pulsegenBegin(void)
Helper function to be called at the beginning of pulsegen()
Definition: GERequired.e:2527

◆ mps2()

STATUS mps2 ( void  )
309  {
310 
311  rspent = L_MPS2;
312  strcpy(psdexitarg.text_arg, "mps2");
313 
314  if (ksfse_scan_init() == FAILURE)
315  return rspexit();
316 
317  if (ksfse_scan_prescanloop(30000, ksfse_dda) == FAILURE)
318  return rspexit();
319 
320  rspexit();
321 
322  return SUCCESS;
323 
324 } /* mps2() */
STATUS ksfse_scan_prescanloop(int nloops, int dda)
Prescan loop called from both APS2 and MPS2 entry points
Definition: ksfse_implementation.e:2892
STATUS ksfse_scan_init(void)
Common initialization for prescan entry points MPS2 and APS2 as well as the SCAN entry point...
Definition: ksfse_implementation.e:2866
int ksfse_dda
Definition: ksfse_implementation.e:127
int rspent
Definition: GERequired.e:2626
PSD_EXIT_ARG psdexitarg

◆ aps2()

STATUS aps2 ( void  )
332  {
333 
334  rspent = L_APS2;
335  strcpy(psdexitarg.text_arg, "aps2");
336 
337  if (ksfse_scan_init() == FAILURE)
338  return rspexit();
339 
340  if (ksfse_scan_prescanloop(100, ksfse_dda) == FAILURE)
341  return rspexit();
342 
343  rspexit();
344 
345  return SUCCESS;
346 
347 } /* aps2() */
STATUS ksfse_scan_prescanloop(int nloops, int dda)
Prescan loop called from both APS2 and MPS2 entry points
Definition: ksfse_implementation.e:2892
STATUS ksfse_scan_init(void)
Common initialization for prescan entry points MPS2 and APS2 as well as the SCAN entry point...
Definition: ksfse_implementation.e:2866
int ksfse_dda
Definition: ksfse_implementation.e:127
int rspent
Definition: GERequired.e:2626
PSD_EXIT_ARG psdexitarg

◆ scan()

STATUS scan ( void  )
356  {
357 
358  rspent = L_SCAN;
359  strcpy(psdexitarg.text_arg, "scan");
360 
361  if (ksfse_scan_init() == FAILURE)
362  return rspexit();
363 
364  /* Scan hierarchy:
365 
366  Without inversion:
367  ksfse_scan_scanloop() - Data for the entire scan
368  ksfse_scan_acqloop() - All data for one set of slices that fit within one TR (one acquisition)
369  ksfse_scan_sliceloop() - One set of slices that fit within one TR played out for one shot
370  ksfse_scan_coreslice() - One slice playout, with optional other sequence modules
371 
372  With inversion:
373  ksfse_scan_scanloop() - Data for the entire scan
374  ksfse_scan_acqloop() - All data for one set of slices that fit within one TR (one acquisition)
375  ksinv_scan_sliceloop() - One set of slices that fit within one TR played out for one shot
376  using the sliceloop in KSInversion.e. Note that ksinv_scan_sliceloop()
377  takes over the TR timing from ksfse_scan_sliceloop() and uses a
378  function pointer to ksfse_scan_coreslice_nargs() to execute the
379  contents of ksfse_scan_coreslice().
380  */
382 
383  GEReq_endofscan();
384 
385  /* So we can see the sequence in plotter after scan completes */
387 
388  rspexit();
389 
390  return SUCCESS;
391 
392 } /* scan() */
STATUS ksfse_scan_init(void)
Common initialization for prescan entry points MPS2 and APS2 as well as the SCAN entry point...
Definition: ksfse_implementation.e:2866
void ks_scan_switch_to_sequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1356
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int GEReq_endofscan()
Sets SSP word in sequence off_GEpass() to tell system that scan is done
Definition: GERequired.e:2590
float ksfse_scan_scanloop()
Plays out all volumes and passes of a single or multi-pass scan
Definition: ksfse_implementation.e:2814
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
int rspent
Definition: GERequired.e:2626
PSD_EXIT_ARG psdexitarg

◆ abstract()

abstract ( "FSE "  [KSFoundation])

◆ psdname()

psdname ( "ksfse"  )

◆ ksfse_eval_TEmenu()

void ksfse_eval_TEmenu ( int  esp,
int  maxte,
int  etl,
double  optechono 
)

Sets up the TE menu based on echo spacing, max TE, ETL and the optimal echo index

optechono is the echo index in range [0, ETL-1] that is in the center of the FSE train. If the TE corresponding to this index is chosen, optimal image quality is achieved with minimal FSE ghosting.

For ETLs > 6, this value is given first in the TE menu, meaning that if the user chooses the first field in the TE menu this will have the same effect as setting "ETL controls TE", and the remaining TE fields in the menu are the ones straddling the optimal TE.

For ETLs in range [2,6], MinFull is the first, followed by the optimal TE.

For ETL = 1, which corresponds to a conventional Spin-Echo, the user can choose only between MinTE (partial kx Fourier) and MinFullTE. Manual type-in is not allowed for ETL = 1.

Returns
void
802  {
803  int allow_typein = 1;
804 
805  if (etl > 6) {
806  pite1val2 = optechono * esp; /* best TE for image quality (minimal T2-blurring, ghosting) */
807  pite1val3 = (optechono - 2) * esp;
808  pite1val4 = (optechono - 1) * esp;
809  pite1val5 = (optechono + 1) * esp;
810  pite1val6 = (optechono + 2) * esp;
811  } else if (etl > 1) {
812  pite1val2 = PSD_MINFULLTE;
813  pite1val3 = (optechono - 2) * esp;
814  pite1val4 = (optechono - 1) * esp;
815  pite1val5 = optechono * esp;
816  pite1val6 = (optechono + 1) * esp;
817  } else { /* etl = 1 */
818  allow_typein = 0;
819  pite1val2 = PSD_MINIMUMTE;
820  pite1val3 = PSD_MINFULLTE;
821  pite1val4 = 0;
822  pite1val5 = 0;
823  pite1val6 = 0;
824  }
825 
826  if (etl > 1) {
827  pite1nub = allow_typein + 2 +
828  4 * (pite1val3 >= esp && pite1val3 <= maxte) +
829  8 * (pite1val4 >= esp && pite1val4 <= maxte) +
830  16 * (pite1val5 >= esp && pite1val5 <= maxte) +
831  32 * (pite1val6 >= esp && pite1val6 <= maxte);
832  } else {
833  pite1nub = 6; /* only MinTE & MinFull */
834  }
835 
836 } /* ksfse_eval_TEmenu() */

◆ ksfse_calc_echo()

STATUS ksfse_calc_echo ( double *  bestecho,
double *  optecho,
KS_PHASER pe,
int  TE,
int  etl,
int  esp 
)

◆ ksfse_pg()

STATUS ksfse_pg ( int  start_time)

The ksfse (main) pulse sequence

This is the main pulse sequence in ksfse.e using the sequence objects in KSFSE_SEQUENCE with the sequence module name "ksfsemain" (= ksfse.seqctrl.description)

Return values
STATUSSUCCESS or FAILURE
2102  {
2103 
2104  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
2105  int readpos_start = KS_NOTSET;
2106  int spoiler_pos = KS_NOTSET;
2107  int i;
2108 
2109  if (start_time < KS_RFSSP_PRETIME) {
2110  return ks_error("%s: 1st arg (pos start) must be at least %d us", __FUNCTION__, KS_RFSSP_PRETIME);
2111  }
2112 
2113 
2114  /*******************************************************************************************************
2115  * RF Excitation
2116  *******************************************************************************************************/
2117  tmploc.ampscale = 1.0;
2118  tmploc.pos = RUP_GRD(start_time + KS_RFSSP_PRETIME);
2119  tmploc.board = ZGRAD;
2120 
2121  /* N.B.: ks_pg_selrf()->ks_pg_rf() detects that ksfse.selrfexc is an excitation pulse
2122  (ksfse.selrfexc.rf.role = KS_RF_ROLE_EXC) and will also set ksfse.seqctrl.momentstart
2123  to the absolute position in [us] of the isocenter of the RF excitation pulse */
2124  if (ks_pg_selrf(&ksfse.selrfexc, tmploc, &ksfse.seqctrl) == FAILURE)
2125  return FAILURE;
2126 
2127 
2128  /*******************************************************************************************************
2129  * X dephaser (between 90 and 1st 180)
2130  *******************************************************************************************************/
2131  if (ksfse_slicecheck) {
2133  tmploc.board = ZGRAD;
2134  } else {
2136  tmploc.board = XGRAD;
2137  }
2138  if (ks_pg_trap(&ksfse.readdephaser, tmploc, &ksfse.seqctrl) == FAILURE)
2139  return FAILURE;
2140 
2141  /*******************************************************************************************************
2142  * Generate the refocusing flip angles
2143  -------------------------------------------------------------------------------------------------------*/
2144  double flip_angles[512]; /* rad */
2145 
2146  if (ksfse_vfa) {
2147 
2148  STATUS status = ks_pg_fse_flip_angle_taperoff(flip_angles,
2149  opetl,
2151  80.0, /* degrees */
2152  opflair != OPFLAIR_INTERLEAVED);
2153  if (status != SUCCESS) return ks_error("ks_pg_fse_flip_angle_taperoff failed");
2154 
2155  /* modify rfpulse-struct for SAR calcs. */
2157  flip_angles,
2158  opetl);
2159 
2160  }
2161 
2162 
2163 
2164  /*******************************************************************************************************
2165  * FSE train: Begin
2166  -------------------------------------------------------------------------------------------------------*/
2167  for (i = 0; i < opetl; i++) {
2168 
2169  /* Selective RF Refocus with left (pregrad.) and right (postgrad.) crushers */
2170  tmploc.board = ZGRAD;
2171  if (i == 0) {
2172  /* special case for 1st pulse with at least a smaller left crusher */
2174 
2175  if (ksfse_vfa)
2176  tmploc.ampscale = flip_angles[i] / ksfse.selrfref1st.rf.flip;
2177 
2178  if (ks_pg_selrf(&ksfse.selrfref1st, tmploc, &ksfse.seqctrl) == FAILURE)
2179  return FAILURE;
2180  tmploc.ampscale = 1;
2181 
2182  } else if (i == 1) {
2184 
2185  if (ksfse_vfa)
2186  tmploc.ampscale = flip_angles[i] / ksfse.selrfref2nd.rf.flip;
2187 
2188  if (ks_pg_selrf(&ksfse.selrfref2nd, tmploc, &ksfse.seqctrl) == FAILURE)
2189  return FAILURE;
2190  tmploc.ampscale = 1;
2191 
2192  } else {
2194 
2195  if (ksfse_vfa)
2196  tmploc.ampscale = flip_angles[i] / ksfse.selrfref.rf.flip;
2197 
2198  if (ks_pg_selrf(&ksfse.selrfref, tmploc, &ksfse.seqctrl) == FAILURE)
2199  return FAILURE;
2200  tmploc.ampscale = 1;
2201 
2202  }
2203 
2204  /* ksfse_esp dependent time at beginning of readout ramp */
2205  readpos_start = ksfse.seqctrl.momentstart + (i + 1) * ksfse_esp - ksfse.read.time2center;
2206 
2207  /*******************************************************************************************************
2208  * Readouts
2209  *******************************************************************************************************/
2210  tmploc.pos = readpos_start;
2211  if (ksfse_slicecheck)
2212  tmploc.board = ZGRAD;
2213  else
2214  tmploc.board = XGRAD;
2215  if (ks_pg_readtrap(&ksfse.read, tmploc, &ksfse.seqctrl) == FAILURE)
2216  return FAILURE;
2217 
2218  /*******************************************************************************************************
2219  * Phase encoding dephasers & rephasers
2220  *******************************************************************************************************/
2221  tmploc.board = YGRAD;
2222  tmploc.pos = readpos_start + ksfse.read.acqdelay - ksfse.phaseenc.grad.duration;
2223  if (ks_pg_phaser(&ksfse.phaseenc, tmploc, &ksfse.seqctrl) == FAILURE) /* instance 2*i */
2224  return FAILURE;
2225  tmploc.pos = readpos_start + ksfse.read.grad.duration - ksfse.read.acqdelay;
2226  if (ks_pg_phaser(&ksfse.phaseenc, tmploc, &ksfse.seqctrl) == FAILURE) /* instance 2*i + 1 */
2227  return FAILURE;
2228 
2229  /*******************************************************************************************************
2230  * Z phase encoding dephasers & rephasers (3D)
2231  *******************************************************************************************************/
2232  if (ksfse.zphaseenc.grad.duration > 0) {
2233  tmploc.board = ZGRAD;
2234  tmploc.pos = readpos_start + ksfse.read.acqdelay - ksfse.zphaseenc.grad.duration;
2235  if (ks_pg_phaser(&ksfse.zphaseenc, tmploc, &ksfse.seqctrl) == FAILURE) /* instance 2*i */
2236  return FAILURE;
2237  tmploc.pos = readpos_start + ksfse.read.grad.duration - ksfse.read.acqdelay;
2238  if (ks_pg_phaser(&ksfse.zphaseenc, tmploc, &ksfse.seqctrl) == FAILURE) /* instance 2*i + 1 */
2239  return FAILURE;
2240  }
2241 
2242  } /* opetl */
2243 
2244  /*------------------------------------------------------------------------------------------------------
2245  * FSE train: End
2246  *******************************************************************************************************/
2247 
2248 
2249  /*******************************************************************************************************
2250  * Phase encoding table
2251  * written to /usr/g/mrraw/ks_phaseencodingtable.txt (HW) or ./ks_phaseencodingtable.txt (SIM)
2252  *
2253  * Need to call this in ksfse_pg() so it is run both on HOST and TGT. This, since the phase table
2254  * is dynamically allocated in ks_phaseencoding_generate_2Dfse()->ks_phaseencoding_resize()
2255  *
2256  * For 3D, ks_phaseencoding_generate_2Dfse() just repeats the same ETL ky path for every kz. This is just
2257  * for testing, and a better ks_phaseencoding_generate_*** function would be needed to do optimal ky-kz
2258  * trajectory for 3D
2259  *******************************************************************************************************/
2262  KS_PF_EARLY_TE, opte, opetl, ksfse_esp) == FAILURE)
2263  return FAILURE;
2264 
2266 
2267  /* set phase encoding amp as for the first shot in the scan loop so it is displayed in WTools MGDSim */
2269 
2270  /*******************************************************************************************************
2271  * Post-ETL forced recovery: T1-w Optimization / T2 fast Recovery
2272  *******************************************************************************************************/
2273  if (ksfse_recovery) {
2274 
2275  int lastReadoutCenter = ksfse.seqctrl.momentstart + opetl * ksfse_esp;
2276 
2277  /* Place extra refocusing pulse */
2278  tmploc.board = ZGRAD;
2280  tmploc.ampscale = (ksfse_vfa) ? flip_angles[opetl-1] / ksfse.selrfrecoverref.rf.flip : 1;
2281 
2282  if (ks_pg_selrf(&ksfse.selrfrecoverref, tmploc, &ksfse.seqctrl) == FAILURE)
2283  return FAILURE;
2284 
2285  /* Place rewinder of previous readout in order to get back to the center of k-space */
2286  tmploc.pos = lastReadoutCenter + ksfse_esp - ksfse.selrfrecover.rf.start2iso - ksfse.readdephaser.duration;
2287  tmploc.ampscale = 1;
2288  if (ksfse_slicecheck) {
2289  tmploc.board = ZGRAD;
2290  tmploc.pos -= ksfse.selrfrecover.grad.ramptime;
2291  } else {
2292  tmploc.board = XGRAD;
2293  }
2294  if (ks_pg_trap(&ksfse.readdephaser, tmploc, &ksfse.seqctrl) == FAILURE)
2295  return FAILURE;
2296 
2297  /* Place excitation pulse */
2298  tmploc.board = ZGRAD;
2300 
2302  tmploc.ampscale = -1;
2303  } else { /* = KSFSE_RECOVERY_T1WOPT */
2304  tmploc.ampscale = 1;
2305  }
2306  if (ks_pg_selrf(&ksfse.selrfrecover, tmploc, &ksfse.seqctrl) == FAILURE)
2307  return FAILURE;
2308  tmploc.ampscale = 1;
2309 
2310  /* spoiler pos */
2312 
2313  } else {
2314 
2315  /* spoiler pos */
2317 
2318  } /* ksfse_recovery */
2319 
2320  /*******************************************************************************************************
2321  * Gradient spoiler on Y
2322  *******************************************************************************************************/
2323  tmploc.board = YGRAD;
2324  tmploc.pos = spoiler_pos;
2325  tmploc.ampscale = 1;
2326  if (ks_pg_trap(&ksfse.spoiler, tmploc, &ksfse.seqctrl) == FAILURE)
2327  return FAILURE;
2328  tmploc.pos += ksfse.spoiler.duration;
2330 
2331 
2332  /*******************************************************************************************************
2333  * Set the minimal sequence duration (ksfse.seqctrl.min_duration) by calling
2334  * ks_eval_seqctrl_setminduration()
2335  *******************************************************************************************************/
2336 
2337  /* make sure we are divisible by GRAD_UPDATE_TIME (4us) */
2338  tmploc.pos = RUP_GRD(tmploc.pos);
2339 
2340 #ifdef HOST_TGT
2341  /* On HOST only: Sequence duration (ksfse.seqctrl.ssi_time must be > 0 and is added to ksfse.seqctrl.min_duration in ks_eval_seqctrl_setminduration() */
2343  ks_eval_seqctrl_setminduration(&ksfse.seqctrl, tmploc.pos); /* tmploc.pos now corresponds to the end of last gradient in the sequence */
2344 #endif
2345 
2346  return SUCCESS;
2347 
2348 } /* ksfse_pg() */
int ksfse_recovery
Definition: ksfse_implementation.e:101
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
KS_TRAP grad
Definition: KSFoundation.h:1491
int ksfse_eval_ssitime()
Set the SSI time for the sequence
Definition: ksfse_implementation.e:1318
int res
Definition: KSFoundation.h:1678
int start2iso
Definition: KSFoundation.h:944
KS_TRAP grad
Definition: KSFoundation.h:1676
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KS_TRAP spoiler
Definition: ksfse_implementation.e:55
int pos
Definition: KSFoundation.h:389
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
STATUS ks_pg_readtrap(KS_READTRAP *readtrap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl) WARN_UNUSED_RESULT
Places a KS_READTRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1785
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
STATUS ks_pg_phaser(KS_PHASER *phaser, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl) WARN_UNUSED_RESULT
Places a KS_PHASER sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1669
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int32_t i
Definition: KSFoundation_tgt.c:1389
STATUS ks_pg_selrf(KS_SELRF *selrf, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl) WARN_UNUSED_RESULT
Places a KS_SELRF sequence object on a gradient (and RF) board at some position in the pulse sequence...
Definition: KSFoundation_common.c:2204
int momentstart
Definition: KSFoundation.h:1136
void ksfse_spoilamp(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_TRAP *spoiler, int res, int shot)
2DFSE: Updates the spoiler amplitude on hardware during scanning depending on current etl and shot...
Definition: ksfse_implementation.e:2059
KS_READTRAP read
Definition: ksfse_implementation.e:51
int board
Definition: KSFoundation.h:388
void ks_pg_mod_fse_rfpulse_structs(KS_SELRF *rf1, KS_SELRF *rf2, KS_SELRF *rf3, const double *flip_angles, const int etl)
Definition: KSFoundation_common.c:2730
KS_TRAP grad
Definition: KSFoundation.h:1586
float ampscale
Definition: KSFoundation.h:390
float flip
Definition: KSFoundation.h:940
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_TRAP readdephaser
Definition: ksfse_implementation.e:52
KS_RF rf
Definition: KSFoundation.h:1485
STATUS ks_phaseencoding_generate_2Dfse(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, const char *const desc, KS_PHASER *phaser, KS_PHASER *zphaser, ks_enum_pf_earlylate_te pf_direction, int TE, int etl, int esp)
2DFSE: Makes a KS_PHASEENCODING_PLAN depending on etl, desired TE, and echo spacing (esp)...
Definition: KSFoundation_common.c:679
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
STATUS ks_pg_trap(KS_TRAP *trap, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl) WARN_UNUSED_RESULT
Places a KS_TRAP sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:1475
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:387
int iso2end
Definition: KSFoundation.h:945
int ssi_time
Definition: KSFoundation.h:1134
STATUS ks_eval_seqctrl_setminduration(KS_SEQ_CONTROL *seqctrl, int mindur)
Sets the minimum duration and duration fields of a KS_SEQ_CONTROL struct based on some minimum time (...
Definition: KSFoundation_host.c:4281
int ksfse_esp
Definition: ksfse_implementation.e:113
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
void ks_phaseencoding_print(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr)
Print out KS_PHASEENCODING_PLAN to a text file
Definition: KSFoundation_common.c:418
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:208
STATUS ksfse_etlphaseamps(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_PHASER *phaser, KS_PHASER *zphaser, int shot)
Sets the phase encoding amplitudes in the FSE train on hardware using the phase enc. table and shot index
Definition: ksfse_implementation.e:2015
int duration
Definition: KSFoundation.h:585
Definition: ksfse_implementation.e:41
int time2center
Definition: KSFoundation.h:1585
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksfse_implementation.e:62
int ksfse_vfa
Definition: ksfse_implementation.e:87
int acqdelay
Definition: KSFoundation.h:1580
int ramptime
Definition: KSFoundation.h:583
Definition: KSFoundation.h:1899
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60
STATUS ks_pg_fse_flip_angle_taperoff(double *flip_angles, int etl, double flip1, double flip2, double flip3, double target_flip, int start_middle)
Definition: KSFoundation_common.c:2763
#define KS_RFSSP_PRETIME
Definition: KSFoundation.h:152
int ksfse_slicecheck
Definition: ksfse_implementation.e:94

◆ ksfse_scan_coreslice()

int ksfse_scan_coreslice ( const SCAN_INFO *  slice_pos,
int  dabslice,
int  shot,
int  exc 
)

Plays out one slice in real time during scanning together with other active sequence modules

On TGT on the MR system (PSD_HW), this function sets up (ksfse_scan_seqstate()) and plays out the core ksfse sequence with optional sequence modules also called in this function. The low-level function call startseq(), which actually starts the realtime sequence playout is called from within ks_scan_playsequence(), which in addition also returns the time to play out that sequence module (see time += ...).

On HOST (in ksfse_eval_tr()) we call ksfse_scan_sliceloop_nargs(), which in turn calls this function that returns the total time in [us] taken to play out this core slice. These times are increasing in each parent function until ultimately ksfse_scan_scantime(), which returns the total time of the entire scan.

After each call to ks_scan_playsequence(), ks_plot_slicetime() is called to add slice-timing information on file for later PNG/PDF-generation of the sequence. As scanning is performed in real-time and may fail if interrupted, ks_plot_slicetime() will return quietly if it detects both IPG (TGT) and PSD_HW (on the MR scanner). See predownload() for the PNG/PDF generation.

Parameters
[in]slice_posPosition of the slice to be played out (one element in the global ks_scan_info[] array)
[in]dabslice0-based slice index for data storage
[in]shotshot index (over ky and kz)
[in]excExcitation index in range [0, NEX-1], where NEX = number of excitations (opnex)
Return values
coreslicetimeTime taken in [us] to play out one slice with potentially other sequence modules
2515  {
2516  int i;
2517  int dabop, dabview;
2518  TYPDAB_PACKETS acqflag;
2519  int time = 0;
2520  float tloc = 0.0;
2521  KS_PHASEENCODING_COORD coord;
2522 
2523  if (slice_pos != NULL)
2524  tloc = slice_pos->optloc;
2525 
2526 
2527  /*******************************************************************************************************
2528  * SpSat sequence module
2529  *******************************************************************************************************/
2531 
2532 
2533  /*******************************************************************************************************
2534  * Chemsat sequence module
2535  *******************************************************************************************************/
2538  ks_plot_slicetime(&kschemsat.seqctrl, 1, NULL, KS_NOTSET, slice_pos == NULL ? KS_PLOT_NO_EXCITATION : KS_PLOT_STANDARD); /* no slice location for fat sat */
2539 
2540 
2541  /*******************************************************************************************************
2542  * ksfse main sequence module
2543  *******************************************************************************************************/
2544  if (slice_pos != NULL) {
2545  ksfse_scan_rf_on();
2546  ksfse_scan_seqstate(*slice_pos, (ksfse_noph != PSD_ON) ? shot : KS_NOTSET); /* shot. if = KS_NOTSET, no phase encodes */
2547  } else {
2548  ksfse_scan_rf_off(); /* false slice, shut off RF pulses */
2549  }
2550 
2551 
2552  for (i = 0; i < ksfse.read.acq.base.ngenerated; i++) {
2553  /* N.B.: Looping over ksfse.read.acq.base.ngenerated corresponds to:
2554  HOST: No looping since ksfse.read.acq.base.ngenerated is 0 on HOST
2555  TGT: ETL.
2556  This protects calls to loaddab() on HOST
2557  */
2558  coord = ks_phaseencoding_get(&ksfse.phaseenc_plan, i, shot);
2559 
2560  /* data routing control */
2561  acqflag = (shot >= 0 && slice_pos != NULL && coord.ky >= 0 && dabslice >= 0) ? DABON : DABOFF; /* open or close data receiver */
2562  dabop = (exc <= 0) ? DABSTORE : DABADD; /* replace or add to data */
2563 
2564  if (KS_3D_SELECTED) {
2565  if (ks_scan_info[1].optloc > ks_scan_info[0].optloc)
2566  dabslice = (opslquant * opvquant - 1) - coord.kz;
2567  else
2568  dabslice = coord.kz;
2569  }
2570 
2571  dabview = (shot >= 0) ? coord.ky : KS_NOTSET;
2572 
2573  if (ksfse.phaseenc.R > 1 && ksfse.phaseenc.nacslines == 0 && dabview != KS_NOTSET) {
2574  /* ASSET case triggered by R > 1 and no ACS lines */
2575  dabview /= ksfse.phaseenc.R; /* store in compressed BAM without empty non-acquired lines */
2576  }
2577 
2578  loaddab(&ksfse.read.acq.echo[i], dabslice, 0, dabop, dabview + 1, acqflag, PSD_LOAD_DAB_ALL); /* see epicfuns.h for alternatives to loaddab() */
2579 
2580  } /* etl */
2581 
2583  ks_plot_slicetime(&ksfse.seqctrl, 1, &tloc, opslthick, slice_pos == NULL ? KS_PLOT_NO_EXCITATION : KS_PLOT_STANDARD);
2584 
2585  return time; /* in [us] */
2586 
2587 } /* ksfse_scan_coreslice() */
int ksspsat_scan_playsequences(int perform_slicetimeplot)
Definition: KSSpSat.e:819
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
int R
Definition: KSFoundation.h:1680
WF_PULSE * echo
Definition: KSFoundation.h:738
int nacslines
Definition: KSFoundation.h:1681
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ksfse_scan_seqstate(SCAN_INFO slice_info, int shot)
Sets the current state of all ksfse sequence objects being part of KSFSE_SEQUENCE
Definition: ksfse_implementation.e:2383
void kschemsat_scan_seqstate(KSCHEMSAT_SEQUENCE *kschemsat)
Sets the current state of all kschemsat sequence objects being part of KSCHEMSAT_SEQUENCE
Definition: KSChemSat.e:388
int ks_perform_slicetimeplot
Definition: GERequired.e:222
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int32_t i
Definition: KSFoundation_tgt.c:1389
int ky
Definition: KSFoundation.h:1705
KS_READTRAP read
Definition: ksfse_implementation.e:51
int kz
Definition: KSFoundation.h:1706
KS_BASE base
Definition: KSFoundation.h:731
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1704
KS_PHASEENCODING_COORD ks_phaseencoding_get(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int echo, int shot)
Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given echo and shot
Definition: KSFoundation_common.c:375
void ksfse_scan_rf_on()
Sets all RF pulse amplitudes on
Definition: ksfse_implementation.e:2477
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1368
Definition: KSFoundation.h:336
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
Definition: KSFoundation.h:335
int ksfse_noph
Definition: ksfse_implementation.e:118
void ks_plot_slicetime(KS_SEQ_CONTROL *ctrl, int nslices, float *slicepos_mm, float slthick_mm, KS_PLOT_EXCITATION_MODE exctype)
Definition: KSFoundation_common.c:3404
void ksfse_scan_rf_off()
Sets all RF pulse amplitudes to zero
Definition: ksfse_implementation.e:2460
int ngenerated
Definition: KSFoundation.h:410
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71
KS_READ acq
Definition: KSFoundation.h:1574
float opslthick
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksfse_implementation.e:62
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksfse_scan_coreslice_nargs()

int ksfse_scan_coreslice_nargs ( const SCAN_INFO *  slice_pos,
int  dabslice,
int  nargs,
void **  args 
)

Wrapper function to ksfse_scan_coreslice() with standardized input arguments

KSInversion.e has functions (ksinv_eval_multislice(), ksinv_eval_checkTR_SAR() and ksinv_scan_sliceloop()) that expect a standardized function pointer to the coreslice function of a main sequence. When inversion mode is enabled for the sequence, ksinv_scan_sliceloop() is used instead of ksfse_scan_sliceloop() in ksfse_scan_acqloop(), and the generic ksinv_scan_sliceloop() function need a handle to the coreslice function of the main sequence.

In order for these ksinv_*** functions to work for any pulse sequence they need a standardized function pointer with a fixed set of input arguments. As different pulse sequences may need different number of input arguments (with different meaning) this ksfse_scan_coreslice_nargs() wrapper function provides the argument translation for ksfse_scan_coreslice().

The function pointer must have SCAN_INFO and slice storage index (dabslice) as the first two input args, while remaining input arguments (to ksfse_scan_coreslice()) are stored in the generic void pointer array with nargs elements, which is then unpacked before calling ksfse_scan_coreslice().

Parameters
[in]slice_posPointer to the SCAN_INFO struct corresponding to the current slice to be played out
[in]dabslice0-based slice index for data storage
[in]nargsNumber of extra input arguments to ksfse_scan_coreslice() in range [0,2]
[in]argsVoid pointer array pointing to the variables containing the actual values needed for ksfse_scan_coreslice()
Return values
coreslicetimeTime taken in [us] to play out one slice with potentially other sequence modules
2618  {
2619  int shot = 0;
2620  int exc = 0;
2621 
2622  if (nargs < 0 || nargs > 2) {
2623  ks_error("%s: 4th arg (void **) must contain up to 2 elements in the following order: shot, exc", __FUNCTION__);
2624  return -1;
2625  } else if (nargs > 0 && args == NULL) {
2626  ks_error("%s: 4th arg (void **) cannot be NULL if nargs (3rd arg) != 0", __FUNCTION__);
2627  return -1;
2628  }
2629 
2630  if (nargs >= 1 && args[0] != NULL) {
2631  shot = *((int *) args[0]);
2632  }
2633  if (nargs >= 2 && args[1] != NULL) {
2634  exc = *((int *) args[1]);
2635  }
2636 
2637  return ksfse_scan_coreslice(slice_pos, dabslice, /* psd specific: */ shot, exc); /* in [us] */
2638 
2639 } /* ksfse_scan_coreslice_nargs() */
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ksfse_scan_coreslice(const SCAN_INFO *slice_pos, int dabslice, int shot, int exc)
Plays out one slice in real time during scanning together with other active sequence modules...
Definition: ksfse_implementation.e:2515

◆ ksfse_scan_sliceloop()

int ksfse_scan_sliceloop ( int  slperpass,
int  passindx,
int  shot,
int  exc 
)

Plays out slperpass slices corresponding to one TR

This function gets a spatial slice location index based on the pass index and temporal position within current pass. It then calls ksfse_scan_coreslice() to play out one coreslice (i.e. the main ksfse main sequence + optional sequence modules, excluding inversion modules).

Parameters
[in]slperpassNumber of slices to play in the slice loop
[in]passindxPass index in range [0, ks_slice_plan.npasses - 1]
[in]shotshot index in range [0, ksfse.phaseenc_plan.num_shots - 1]
[in]excExcitation index in range [0, NEX-1], where NEX = number of excitations (opnex)
Return values
slicelooptimeTime taken in [us] to play out slperpass slices
2658  {
2659  int time = 0;
2660  int slloc, sltimeinpass;
2661  SCAN_INFO centerposition = ks_scan_info[0]; /* first slice chosen here, need only rotation stuff */
2662 
2663  if (KS_3D_SELECTED) {
2664  int centerslice = opslquant/2;
2665  /* for future 3D multislab support, let passindx update centerposition */
2666  centerposition.optloc = (ks_scan_info[centerslice-1].optloc + ks_scan_info[centerslice].optloc)/2.0;
2667  }
2668 
2669  for (sltimeinpass = 0; sltimeinpass < slperpass; sltimeinpass++) {
2670 
2671  SCAN_INFO *current_slice = &centerposition;
2672 
2673  if (!KS_3D_SELECTED) { /* 2D */
2674  /* slice location from slice plan */
2675  slloc = ks_scan_getsliceloc(&ks_slice_plan, passindx, sltimeinpass);
2676 
2677  /* if slloc = KS_NOTSET, pass in NULL as first argument to indicate 'false slice' */
2678  current_slice = (slloc != KS_NOTSET) ? &ks_scan_info[slloc]: NULL;
2679  }
2680 
2681  time += ksfse_scan_coreslice(current_slice, sltimeinpass, shot, exc);
2682 
2683  }
2684 
2685  return time; /* in [us] */
2686 
2687 } /* ksfse_scan_sliceloop() */
#define KS_NOTSET
Definition: KSFoundation.h:103
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int passindx
Definition: ksfse_implementation.e:2849
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
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
int ksfse_scan_coreslice(const SCAN_INFO *slice_pos, int dabslice, int shot, int exc)
Plays out one slice in real time during scanning together with other active sequence modules...
Definition: ksfse_implementation.e:2515
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksfse_scan_sliceloop_nargs()

int ksfse_scan_sliceloop_nargs ( int  slperpass,
int  nargs,
void **  args 
)

Wrapper function to ksfse_scan_sliceloop() with standardized input arguments

For TR timing heat/SAR calculations of regular 2D multislice sequences, GEReq_eval_TR(), ks_eval_mintr() and GEReq_eval_checkTR_SAR() use a standardized function pointer with a fixed set of input arguments to call the sliceloop of the main sequence with different number of slices to check current slice loop duration. As different pulse sequences may need different number of input arguments (with different meaning) this ksfse_scan_sliceloop_nargs() wrapper function provides the argument translation for ksfse_scan_sliceloop().

The function pointer must have an integer corresponding to the number of slices to use as its first argument while the remaining input arguments (to ksfse_scan_sliceloop()) are stored in the generic void pointer array with nargs elements, which is then unpacked before calling ksfse_scan_sliceloop().

Parameters
[in]slperpassNumber of slices to play in the slice loop
[in]nargsNumber of extra input arguments to ksfse_scan_sliceloop() in range [0,4]
[in]argsVoid pointer array pointing to the variables containing the actual values needed for ksfse_scan_sliceloop()
Return values
slicelooptimeTime taken in [us] to play out slperpass slices
2713  {
2714  int passindx = 0;
2715  int shot = KS_NOTSET; /* off */
2716  int exc = 0;
2717 
2718  if (nargs < 0 || nargs > 3) {
2719  ks_error("%s: 3rd arg (void **) must contain up to 3 elements: passindx, shot, exc", __FUNCTION__);
2720  return -1;
2721  } else if (nargs > 0 && args == NULL) {
2722  ks_error("%s: 3rd arg (void **) cannot be NULL if nargs (2nd arg) != 0", __FUNCTION__);
2723  return -1;
2724  }
2725 
2726  if (nargs >= 1 && args[0] != NULL) {
2727  passindx = *((int *) args[0]);
2728  }
2729  if (nargs >= 2 && args[1] != NULL) {
2730  shot = *((int *) args[1]);
2731  }
2732  if (nargs >= 3 && args[2] != NULL) {
2733  exc = *((int *) args[2]);
2734  }
2735 
2736  return ksfse_scan_sliceloop(slperpass, passindx, shot, exc); /* in [us] */
2737 
2738 } /* ksfse_scan_sliceloop_nargs() */
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int ksfse_scan_sliceloop(int slperpass, int passindx, int shot, int exc)
Plays out slperpass slices corresponding to one TR
Definition: ksfse_implementation.e:2658
int passindx
Definition: ksfse_implementation.e:2849

◆ ksfse_scan_acqloop()

float ksfse_scan_acqloop ( int  passindx)

Plays out all phase encodes for all slices belonging to one pass

This function traverses through all shots (ksfse.phaseenc_plan.num_shots) to be played out and runs the ksfse_scan_sliceloop() for each set of shots and excitation. If ksfse_dda > 0, dummy scans will be played out before the phase encoding begins.

In the case of inversion, ksinv_scan_sliceloop() is called instead of ksfse_scan_sliceloop(), where the former takes a function pointer to ksfse_scan_coreslice_nargs() in order to be able to play out the coreslice in a timing scheme set by ksinv_scan_sliceloop().

Parameters
[in]passindx0-based pass index in range [0, ks_slice_plan.npasses - 1]
Return values
passlooptimeTime taken in [us] to play out all phase encodes and excitations for slperpass slices. Note that the value is a float instead of int to avoid int overrange at 38 mins of scanning
2760  {
2761  float time = 0.0;
2762  int shot, exc;
2763 
2764  for (shot = -ksfse_dda; shot < ksfse.phaseenc_plan.num_shots; shot++) {
2765 
2766  /* shot < 0 means dummy scans, and is handled in ksfse_scan_coreslice(), ksfse_scan_seqstate() and ksfse_etlphaseamps() */
2767 
2768  if (shot == 0 && ksfse_dda > 0) {
2770  }
2771 
2772  for (exc = 0; exc < (int) ceil(opnex); exc++) { /* ceil rounds up opnex < 1 (used for partial Fourier) to 1 */
2773 
2774  if (ksinv1.params.irmode != KSINV_OFF) {
2775  void *args[2] = {(void *) &shot, (void *) &exc}; /* pass on args via ksinv_scan_sliceloop() to ksfse_scan_coreslice() */
2776  int nargs = sizeof(args) / sizeof(void *);
2778  (shot < 0) ? KSINV_LOOP_DUMMY : KSINV_LOOP_NORMAL, ksfse_scan_coreslice_nargs, nargs, args);
2779  } else {
2780  time += (float) ksfse_scan_sliceloop(ks_slice_plan.nslices_per_pass, passindx, shot, exc);
2781  }
2782 
2783  ks_plot_slicetime_endofslicegroup("ksfse shots");
2784 
2785  } /* for exc */
2786 
2787  /* save a frame of the main sequence for later generation of an animated GIF (only in MgdSim, WTools) */
2788  if (shot >= 0) {
2790  }
2791 
2792  } /* for shot */
2793 
2795  return time; /* in [us] */
2796 
2797 } /* ksfse_scan_acqloop() */
int num_shots
Definition: KSFoundation.h:1739
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE)
Definition: KSFoundation_common.c:3412
int ksfse_scan_sliceloop(int slperpass, int passindx, int shot, int exc)
Plays out slperpass slices corresponding to one TR
Definition: ksfse_implementation.e:2658
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
void ks_plot_tgt_addframe(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_common.c:3488
void ks_plot_slicetime_endofslicegroup(const char *desc)
Definition: KSFoundation_common.c:3428
int irmode
Definition: KSInversion.e:76
int nslices_per_pass
Definition: KSFoundation.h:1353
Definition: KSFoundation.h:339
Definition: KSInversion.e:47
int ksfse_scan_coreslice_nargs(const SCAN_INFO *slice_pos, int dabslice, int nargs, void **args)
Wrapper function to ksfse_scan_coreslice() with standardized input arguments
Definition: ksfse_implementation.e:2618
int ksinv_scan_sliceloop(const KS_SLICE_PLAN *slice_plan, const SCAN_INFO *slice_positions, int passindx, KSINV_SEQUENCE *ksinv1, KSINV_SEQUENCE *ksinv2, KS_SEQ_CONTROL *ksinv_filltr, KSINV_LOOP_MODE ksinv_loop_mode, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
Plays out slice_plan.nslices_per_pass slices corresponding to one TR for inversion psds...
Definition: KSInversion.e:2257
int passindx
Definition: ksfse_implementation.e:2849
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
int ksfse_dda
Definition: ksfse_implementation.e:127
Definition: KSInversion.e:47
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
Definition: KSFoundation.h:341
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksfse_implementation.e:62
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksfse_scan_scanloop()

float ksfse_scan_scanloop ( )

Plays out all volumes and passes of a single or multi-pass scan

This function performs the entire scan and traverses through passes and volumes. For now, since opmph = 0 as multiphase is controlled outside the psd via PSD_IOPT_DYNPL, opfphases will always be 1. For each passindx (in range [0, ks_slice_plan.npasses-1]), ksfse_scan_acqloop() will be called to acquire all data for the current set of slices belong to the current pass (acquisition). At the end of each pass, GEReq_endofpass() is called to trigger GE's recon and to dump Pfiles (if autolock = 1).

Return values
scantimeTotal scan time in [us] (float to avoid int overrange after 38 mins)
2814  {
2815  float time = 0.0;
2816 
2817  for (volindx = 0; volindx < opfphases; volindx++) { /* opfphases is # volumes (BUT: opfphases always 1 since opmph = 0) */
2818 
2819  for (passindx = 0; passindx < ks_slice_plan.npasses; passindx++) { /* acqs = passes */
2820 
2821  time += ksfse_scan_acqloop(passindx);
2822 
2823 #ifdef IPG
2824  GEReq_endofpass();
2825 #endif
2826 
2827  } /* end: acqs (pass) loop */
2828 
2829  } /* end: volume loop */
2830 
2831  return time; /* in [us] */
2832 
2833 } /* ksfse_scan_acqloop() */
int volindx
Definition: ksfse_implementation.e:2849
int npasses
Definition: KSFoundation.h:1352
float ksfse_scan_acqloop(int)
Plays out all phase encodes for all slices belonging to one pass
Definition: ksfse_implementation.e:2760
int passindx
Definition: ksfse_implementation.e:2849
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:2574
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217

◆ ksfse_scan_seqstate()

STATUS ksfse_scan_seqstate ( SCAN_INFO  slice_info,
int  shot 
)

Sets the current state of all ksfse sequence objects being part of KSFSE_SEQUENCE

This function sets the current state of all ksfse sequence objects being part of KSFSE_SEQUENCE, incl. gradient amplitude changes, RF freq/phases and receive freq/phase based on current slice position and phase encoding indices.

The idea of having a 'seqstate' function is to be able to come back to a certain sequence state at any time and possibly play it out once more. This could for example be useful when certain lines or slices need to be rescanned due to image artifacts detected during scanning.

Parameters
[in]slice_infoPosition of the slice to be played out (one element in the ks_scan_info[] array)
[in]shotshot index in range [0, ksfse.phaseenc_plan.num_shots - 1]
Return values
STATUSSUCCESS or FAILURE
2383  {
2384  int i;
2385  float rfphase = 0.0;
2386  KS_PHASEENCODING_COORD coord;
2387 
2388  ks_scan_rotate(slice_info);
2389 
2390  ks_scan_selrf_setfreqphase(&ksfse.selrfexc, 0, slice_info, rfphase /* [deg] */);
2391  ks_scan_selrf_setfreqphase(&ksfse.selrfref1st, INSTRALL, slice_info, rfphase + 90 /* [deg] */);
2392  ks_scan_selrf_setfreqphase(&ksfse.selrfref2nd, INSTRALL, slice_info, rfphase + 90 /* [deg] */);
2393  ks_scan_selrf_setfreqphase(&ksfse.selrfref, INSTRALL, slice_info, rfphase + 90 /* [deg] */);
2394  if (ksfse_recovery) {
2395  ks_scan_selrf_setfreqphase(&ksfse.selrfrecoverref, INSTRALL, slice_info, rfphase + 90 /* [deg] */);
2396  ks_scan_selrf_setfreqphase(&ksfse.selrfrecover, 0, slice_info, rfphase /* [deg] */);
2397  }
2398 
2399  /* FOV offsets (by changing freq/phase of ksfse.read) */
2400  if (shot >= 0) {
2401  for (i = 0; i < ksfse.phaseenc_plan.etl; i++) {
2402 
2403  coord = ks_phaseencoding_get(&ksfse.phaseenc_plan, i, shot);
2404  float ky_centred;
2405  if (coord.ky < 0) {
2406  ky_centred = 0.0f;
2407  } else {
2408  ky_centred = (float)coord.ky - (float)(ksfse.phaseenc.res - 1) / 2.0f;
2409  }
2410 
2411  if (KS_3D_SELECTED) {
2412  float zfovratio = (opslquant * opslthick) / opfov;
2413  float zchop_phase = 0.0;
2414  float kz_centred;
2415  if (coord.kz < 0) {
2416  kz_centred = 0.0f;
2417  } else {
2418  kz_centred = (float)coord.kz - (float)(ksfse.zphaseenc.res - 1) / 2.0f;
2419  }
2420  if (oparc && (coord.kz % 2)) {
2421  /* GEs ARC recon ignores RHF_ZCHOP bit in 'rhformat', but expects 3D data to be z-chopped for proper slice sorting.
2422  In GERequired.e:GEReq_predownload_setrecon_voldata(), RHF_ZCHOP is unset by default. In combination with
2423  that we do not do zchop for non-ARC scans (incl ASSET), this works well. But for ARC scans, we must zchop. That is,
2424  we add 180 phase to every odd kz encoded line, which is the same as a final z fftshift in the image domain */
2425  zchop_phase = 180.0;
2426  }
2427  ks_scan_offsetfov3D(&ksfse.read, i, slice_info, ky_centred, opphasefov, kz_centred, zfovratio, rfphase + zchop_phase);
2428  } else {
2429  ks_scan_offsetfov(&ksfse.read, i, slice_info, ky_centred, opphasefov, rfphase);
2430  }
2431 
2432  } /* etl */
2433  } /* shot > 0 */
2434 
2435  /* change phase encoding amplitudes */
2437 
2438  /* change spoiler amplitude */
2440 
2441  /* Turn off T1-w opt. in DDAs */
2442  if ((ksfse_recovery) && (shot < 0)) {
2445  }
2446 
2447  return SUCCESS;
2448 
2449 } /* ksfse_scan_seqstate() */
int ksfse_recovery
Definition: ksfse_implementation.e:101
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
int res
Definition: KSFoundation.h:1678
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KS_TRAP spoiler
Definition: ksfse_implementation.e:55
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int32_t i
Definition: KSFoundation_tgt.c:1389
int ky
Definition: KSFoundation.h:1705
void ksfse_spoilamp(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_TRAP *spoiler, int res, int shot)
2DFSE: Updates the spoiler amplitude on hardware during scanning depending on current etl and shot...
Definition: ksfse_implementation.e:2059
KS_READTRAP read
Definition: ksfse_implementation.e:51
void ks_scan_rf_off(KS_RF *rf, int instanceno)
Sets the amplitude of one or all instances of an RF pulse (KS_RF) to zero
Definition: KSFoundation_tgt.c:469
int kz
Definition: KSFoundation.h:1706
void ks_scan_offsetfov3D(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float kyview, float phasefovratio, float kzview, float zphasefovratio, float rcvphase)
Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift...
Definition: KSFoundation_tgt.c:974
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1704
KS_PHASEENCODING_COORD ks_phaseencoding_get(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int echo, int shot)
Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given echo and shot
Definition: KSFoundation_common.c:375
void ks_scan_selrf_setfreqphase(KS_SELRF *selrf, int instanceno, SCAN_INFO sliceinfo, float rfphase)
Updates the frequency and phase of one or all instances of a slice selective RF pulse (KS_SELRF)...
Definition: KSFoundation_tgt.c:581
KS_RF rf
Definition: KSFoundation.h:1485
int etl
Definition: KSFoundation.h:1740
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
float opfov
void ks_scan_rotate(SCAN_INFO slice_info)
Performs a rotation of the logical system on hardware (WARP)
Definition: KSFoundation_tgt.c:989
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
void ks_scan_offsetfov(KS_READTRAP *readtrap, int instanceno, SCAN_INFO sliceinfo, float view, float phasefovratio, float rcvphase)
Updates the frequency and phase of one or all instances of a KS_READTRAP to create a FOV shift...
Definition: KSFoundation_tgt.c:968
STATUS ksfse_etlphaseamps(KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, KS_PHASER *phaser, KS_PHASER *zphaser, int shot)
Sets the phase encoding amplitudes in the FSE train on hardware using the phase enc. table and shot index
Definition: ksfse_implementation.e:2015
float opslthick
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksfse_implementation.e:62
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60

◆ ksfse_init_imagingoptions()

void ksfse_init_imagingoptions ( void  )

Initial handling of imaging options buttons and top-level CVs at the PSD type-in pages

Returns
void
226  {
227  int numopts = sizeof(sequence_iopts) / sizeof(int);
228 
229  psd_init_iopt_activity();
230  activate_iopt_list(numopts, sequence_iopts);
231  enable_iopt_list(numopts, sequence_iopts);
232 
233  /* Imaging option control functions (using PSD_IOPT_ZIP_512 as example):
234  - Make an option unchecked and not selectable: disable_ioption(PSD_IOPT_ZIP_512)
235  - Make an option checked and not selectable: set_required_disabled_option(PSD_IOPT_ZIP_512)
236  - Remove the imaging option: deactivate_ioption(PSD_IOPT_ZIP_512)
237  */
238 
239  cvmax(opimode, PSD_3DM);
240 
241  /* Button accept control */
242  cvmax(opepi, PSD_OFF); /* don't allow EPI selection */
243  cvmax(opfast, PSD_ON);
244  cvmax(opssfse, PSD_ON);
245  cvmax(opflair, OPFLAIR_INTERLEAVED);
246  cvmax(optlrdrf, PSD_ON);
247  cvmax(opfr, PSD_ON);
248 
249  /* GE recon does not support ARC for T1FLAIR or T2FLAIR */
250  set_incompatible(PSD_IOPT_ARC, PSD_IOPT_T1FLAIR);
251  set_incompatible(PSD_IOPT_ARC, PSD_IOPT_T2FLAIR);
252 
253  if (KS_3D_SELECTED) {
254  pidefexcitemode = NON_SELECTIVE;
255  piexcitemodenub = 1 + 2 /* + 4 FOCUS */;
256  cvmax(opexcitemode, NON_SELECTIVE);
257 
258  /* For now, 3D is not compatible with: */
259  deactivate_ioption(PSD_IOPT_T1FLAIR);
260  deactivate_ioption(PSD_IOPT_T2FLAIR);
261  deactivate_ioption(PSD_IOPT_IR_PREP);
262  deactivate_ioption(PSD_IOPT_TLRD_RF);
263  }
264 
265 #ifdef SIM
266  oppseq = PSD_SE;
267  setexist(oppseq, PSD_ON);
268  opfast = PSD_ON;
269  setexist(opfast, PSD_ON);
270  opirmode = PSD_OFF; /* default interleaved slices */
271  setexist(opirmode, PSD_ON);
272 #endif
273 
274 } /* ksfse_init_imagingoptions() */
int sequence_iopts[]
Definition: ksfse_implementation.e:196
#define KS_3D_SELECTED
Definition: KSFoundation.h:177

◆ ksfse_init_UI()

STATUS ksfse_init_UI ( void  )

Initial setup of user interface (UI) with default values for menus and fields

Return values
STATUSSUCCESS or FAILURE
284  {
285 
286  /* IR always in interleaved mode */
287  if (oppseq == PSD_IR) {
288  cvoverride(opirmode, PSD_OFF, PSD_FIX_ON, PSD_EXIST_ON);
289  }
290 
291  acq_type = TYPSPIN; /* loadrheader.e rheaderinit: sets eeff = 1 */
292 
293  /* rBW */
294  cvmin(oprbw, 2);
295  cvmax(oprbw, 250.0);
296  pircbnub = 31; /* number of variable bandwidth */
297  if (opssfse == PSD_ON) {
298  pidefrbw = 62.50 * (cffield / 30000.0);
299  } else {
300  pidefrbw = 41.67 * (cffield / 30000.0);
301  }
302  pircbval2 = 31.25 * (cffield / 30000.0);
303  pircbval3 = 41.67 * (cffield / 30000.0);
304  pircbval4 = 50.00 * (cffield / 30000.0);
305  pircbval5 = 62.50 * (cffield / 30000.0);
306  pircbval6 = 83.33 * (cffield / 30000.0);
307  cvdef(oprbw, pidefrbw);
308  oprbw = _oprbw.defval;
309  pircb2nub = 0; /* no second bandwidth option */
310 
311  /* NEX */
312  pinexnub = 63;
313  if (opssfse == PSD_ON) {
314  cvdef(opnex, 0.6);
315  cvmin(opnex, 0.55);
316  cvmax(opnex, 100);
317  pinexval2 = 0.55;
318  pinexval3 = 0.575;
319  pinexval4 = 0.60;
320  pinexval5 = 0.625;
321  pinexval6 = 0.65;
322  } else {
323  cvdef(opnex, 1);
324  cvmin(opnex, 0.55);
325  cvmax(opnex, 100);
326  pinexval2 = 0.65;
327  pinexval3 = 0.75;
328  pinexval4 = 0.85;
329  pinexval5 = 1;
330  pinexval6 = 2;
331  }
332  opnex = _opnex.defval;
333 
334  /* FOV */
335  opfov = 240;
336  pifovnub = 4; /* show the first three + type-in */
337  pifovval2 = 180;
338  pifovval3 = 220;
339  pifovval4 = 240;
340  pifovval5 = 260;
341  pifovval6 = 280;
342 
343  /* phase FOV fraction */
344  opphasefov = 1;
345  piphasfovnub2 = 63;
346  piphasfovval2 = 1.0;
347  piphasfovval3 = 0.9;
348  piphasfovval4 = 0.8;
349  piphasfovval5 = 0.7;
350  piphasfovval6 = 0.6;
351 
352  /* freq (x) resolution */
353  cvmin(opxres, 16);
354  cvdef(opxres, 64);
355  opxres = _opxres.defval;
356  pixresnub = 63;
357  pixresval2 = 192;
358  pixresval3 = 224;
359  pixresval4 = 256;
360  pixresval5 = 320;
361  pixresval6 = 384;
362 
363  /* phase (y) resolution */
364  cvmin(opyres, 16);
365  piyresnub = 63;
366  if (opssfse == PSD_ON) {
367  piyresval2 = 64;
368  piyresval3 = 128;
369  piyresval4 = 160;
370  piyresval5 = 192;
371  piyresval6 = 256;
372  cvdef(opyres, 16); /* init low for SSFSE to avoid too long sequence length before proper values have been chosen */
373  } else {
374  piyresval2 = 192;
375  piyresval3 = 224;
376  piyresval4 = 256;
377  piyresval5 = 320;
378  piyresval6 = 384;
379  cvdef(opyres, 128);
380  }
381  opyres = _opyres.defval;
382 
383  /* Num echoes */
384  piechnub = 0;
385  cvdef(opnecho, 1);
386  cvmax(opnecho, 1);
387 
388  /* ETL */
389  avminetl = 1;
390  avmaxetl = 256;
391  if (opssfse == PSD_ON) {
392 
393  if (ksfse.phaseenc.numlinestoacq > 0)
394  cvdef(opetl, ksfse.phaseenc.numlinestoacq);
395  else
396  cvdef(opetl, _opyres.defval);
397  opetl = _opetl.defval;
398  pietlnub = 0;
399 
400  } else {
401 
402  if (!KS_3D_SELECTED) {
403  /* 2D */
404 
405  if (opflair == FALSE) {
406  if (optr < 1s) {
407  /* T1-w */
408  cvdef(opetl, 1);
409  opetl = _opetl.defval;
410  pietlnub = 63;
411  pietlval2 = 1;
412  pietlval3 = 2;
413  pietlval4 = 3;
414  pietlval5 = 4;
415  pietlval6 = 8;
416  } else {
417  /* T2-w */
418  cvdef(opetl, 16);
419  opetl = _opetl.defval;
420  pietlnub = 63;
421  pietlval2 = 8;
422  pietlval3 = 12;
423  pietlval4 = 16;
424  pietlval5 = 20;
425  pietlval6 = 24;
426  }
427  } else if (opflair == OPFLAIR_GROUP) { /* T2-FLAIR */
428  cvdef(opetl, 24);
429  opetl = _opetl.defval;
430  pietlnub = 63;
431  pietlval2 = 20;
432  pietlval3 = 24;
433  pietlval4 = 28;
434  pietlval5 = 32;
435  pietlval6 = 36;
436  } else if (opflair == OPFLAIR_INTERLEAVED) { /* T1-FLAIR */
437  cvdef(opetl, 8);
438  opetl = _opetl.defval;
439  pietlnub = 63;
440  pietlval2 = 4;
441  pietlval3 = 5;
442  pietlval4 = 6;
443  pietlval5 = 7;
444  pietlval6 = 8;
445  }
446 
447  } else {
448 
449  /* 3D */
450  cvdef(opetl, 32);
451  opetl = _opetl.defval;
452  pietlnub = 63;
453  pietlval2 = 32;
454  pietlval3 = 48;
455  pietlval4 = 64;
456  pietlval5 = 96;
457  pietlval6 = 128;
458  }
459 
460  } /* non-ssfse ETL menu */
461 
462 
463  /* TE */
464  pitetype = PSD_LABEL_TE_EFF; /* alt. PSD_LABEL_TE_EFF */
465  if (! existcv(opte)) {
466  avmaxte = 2s;
467  avminte = 0;
468  cvmin(opte, avminte);
469  cvmax(opte, avmaxte);
470  cvdef(opte, 100ms);
471  opte = _opte.defval;
472  ksfse_eval_TEmenu(10ms /* fake esp */, 200ms /* fake maxte */, opetl, opetl / 2.0);
473  }
474 
475  /* TE2 */
476  pite2nub = 0;
477 
478  /* TR */
479  cvdef(optr, 5s);
480  optr = _optr.defval;
481  /*
482  If you want values (pitrval) in the dropdown menu, change to pitrnub = 6;.
483  Remember that you can control the minimum and maximum TR-range
484  from the advanced tab using opuser18 & 19.
485  */
486  pitrnub = 2;
487  pitrval2 = PSD_MINIMUMTR;
488  pitrval3 = 500ms;
489  pitrval4 = 3000ms;
490  pitrval5 = 4000ms;
491  pitrval6 = 5000ms;
492 
493  /* FA of refocusing pulse */
494  cvmax(opflip, 360);
495  cvdef(opflip, 125); /* set it low to avoid init errors on sequence selection */
496  opflip = _opflip.defval;
497 #if EPIC_RELEASE >= 24
498  pifamode = PSD_FLIP_ANGLE_MODE_REFOCUS;
499  pifanub = 5;
500  pifaval2 = 110;
501  pifaval3 = 125;
502  pifaval4 = 140;
503  pifaval5 = 160;
504 #else
505  pifanub = 0;
506 #endif
507 
508  /* slice thickness */
509  pistnub = 5;
510  if (KS_3D_SELECTED) {
511  cvdef(opslthick, 1);
512  pistval2 = 0.8;
513  pistval3 = 0.9;
514  pistval4 = 1;
515  pistval5 = 1.5;
516  pistval5 = 2;
517  } else {
518  cvdef(opslthick, 4);
519  pistval2 = 2;
520  pistval3 = 3;
521  pistval4 = 4;
522  pistval5 = 5;
523  pistval6 = 10;
524  }
525  opslthick = _opslthick.defval;
526 
527  /* slice spacing */
528  cvdef(opslspace, 0);
529  opslspace = _opslspace.defval;
530  piisil = PSD_ON;
531  if (KS_3D_SELECTED) {
532  /* change these to do overlaps */
533  piisnub = 0;
534  piisval2 = 0;
535  } else {
536  piisnub = 5;
537  piisval2 = 0;
538  piisval3 = 0.5;
539  piisval4 = 1;
540  piisval5 = 2;
541  piisval6 = 3;
542  }
543 
544  /* default # of slices */
545  cvdef(opslquant, 30);
546 
547  /* 3D slice settings */
548  if (KS_3D_SELECTED) { /* PSD_3D or PSD_3DM */
549  pimultislab = 0; /* 0: forces only single slab, 1: allow multi-slab (won't work with non-selective refocusing pulses) */
550  pilocnub = 4;
551  pilocval2 = 28;
552  pilocval3 = 60;
553  pilocval4 = 124;
554  pilocval5 = 252;
555  /* opslquant = #slices in slab. opvquant = #slabs */
556  cvdef(opslquant, 32);
557  }
558 
559  opslquant = _opslquant.defval;
560 
561  /* Multi phase (i.e. multi volumes) (only active if PSD_IOPT_MPH, not PSD_IOPT_DYNPL) */
562  if (opmph) {
563  pimphscrn = 1; /* display Multi-Phase Parameter screen */
564  pifphasenub = 6;
565  pifphaseval2 = 1;
566  pifphaseval3 = 2;
567  pifphaseval4 = 5;
568  pifphaseval5 = 10;
569  pifphaseval6 = 15;
570  pisldelnub = 0;
571  piacqnub = 0;
572  setexist(opacqo, 1);
573  pihrepnub = 0; /* no XRR gating */
574  } else {
575  cvoverride(opfphases, 1, PSD_FIX_ON, PSD_EXIST_ON);
576  }
577 
578  /* opuser0: show GIT revision (GITSHA) using REV variable from the Imakefile */
579  char userstr[100];
580 #ifdef REV
581  sprintf(userstr, " %s PSD version: %s", _ksfse_flipexc.descr, REV);
582 #else
583  sprintf(userstr, "%s", _ksfse_flipexc.descr);
584 #endif
585  cvmod(opuser0, _ksfse_flipexc.minval, _ksfse_flipexc.maxval, _ksfse_flipexc.defval, userstr, 0, " ");
586  opuser0 = _opuser0.defval;
587  piuset |= use0;
588 
589  /* opuser1: TE based on ETL. */
590  cvmod(opuser1, _ksfse_etlte.minval, _ksfse_etlte.maxval, _ksfse_etlte.defval, _ksfse_etlte.descr, 0, " ");
591  opuser1 = _ksfse_etlte.defval;
592  ksfse_etlte = _ksfse_etlte.defval;
593 
594  if (opssfse) {
595  piuset &= ~use1; /* don't show for SSFSE */
596  } else {
597  piuset |= use1; /* show since not SSFSE */
598  }
599 
600  cvmod(opuser2, _ksfse_inflowsuppression.minval, _ksfse_inflowsuppression.maxval, _ksfse_inflowsuppression.defval, _ksfse_inflowsuppression.descr, 0, " ");
601  piuset |= use2;
602  opuser2 = _ksfse_inflowsuppression.defval;
603 
604 
605  if (opfr == FALSE && (oppseq != PSD_IR /* 3 */ && opirprep == FALSE && opflair == FALSE) && opssfse == FALSE && exist(opetl) > 1) {
606  /* if FSE-XL has been selected, allow T1-w optimization */
607  cvmod(opuser3, 0, 1, 0, "T1-w Optimization [0:OFF 1:ON]", 0, " ");
608  opuser3 = _opuser3.defval;
609  piuset |= use3;
610  } else {
611  opuser3 = 0;
612  piuset &= ~use3;
613  }
614 
615 
616  /* In-range TR support (but without using GE's opinrangetr, since we don't know
617  how to read the AutoTR field values on the Advanced tab. Instead, for now, add two opusers
618  for the range. If any of these are = 0, it is disabled */
619  cvmod(opuser4, _ksfse_mintr.minval/1000, _ksfse_mintr.maxval/1000, _ksfse_mintr.defval/1000, _ksfse_mintr.descr, 0, " "); /* minTR in [ms] */
620  opuser4 = _opuser4.defval;
621  piuset |= use4;
622  cvmod(opuser5, _ksfse_maxtr.minval/1000, _ksfse_maxtr.maxval/1000, _ksfse_maxtr.defval/1000, _ksfse_maxtr.descr, 0, " "); /* maxTR in [ms] */
623  opuser5 = _opuser5.defval;
624  if (opflair == OPFLAIR_GROUP) {
625  piuset &= ~use5; /* Don't show maxTR limit for T2FLAIR */
626  } else {
627  piuset |= use5;
628  }
629 
630  if (opflair != OPFLAIR_GROUP) {
631  _rf_stretch_all.defval = 1.5; /* Wider default (except for T2FLAIR which is less SAR heavy) to shorten the scan time (less SAR penalty) */
632  } else {
633  _rf_stretch_all.defval = 1.0;
634  }
635  cvmod(opuser6, 1.0, _rf_stretch_all.maxval, _rf_stretch_all.defval, _rf_stretch_all.descr, 0, " ");
636  opuser6 = _rf_stretch_all.defval;
637  piuset |= use6;
638 
639  /*
640  Reserved opusers:
641  -----------------
642  ksfse_eval_inversion(): opuser26-29
643  GE reserves: opuser36-48 (epic.h)
644  */
645 
646  if (oparc) {
647  /* Acceleration menu as decimal numbers (max accel = 4) */
649  } else {
650  /* Acceleration menu as integers (max accel = 4)
651  Covers the non-accelerated and ASSET cases */
653  }
654 
655 
656  return SUCCESS;
657 
658 } /* ksfse_init_UI() */
Definition: KSFoundation.h:1950
int opxres
int opyres
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int numlinestoacq
Definition: KSFoundation.h:1684
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
Definition: KSFoundation.h:1950
float opfov
STATUS GEReq_init_accelUI(int integeraccel, int maxaccel)
Sets up the menu for parallel imaging (ARC or ASSET) with max/min range
Definition: GERequired.e:432
float opslthick
void ksfse_eval_TEmenu(int esp, int maxte, int etl, double optechono)
Sets up the TE menu based on echo spacing, max TE, ETL and the optimal echo index
Definition: ksfse_implementation.e:802
int ksfse_etlte
Definition: ksfse_implementation.e:111

◆ ksfse_eval_UI()

STATUS ksfse_eval_UI ( )

Gets the current UI and checks for valid inputs

Return values
STATUSSUCCESS or FAILURE
678  {
679 
680  if (ksfse_init_UI() == FAILURE)
681  return FAILURE;
682 
683 
684 
685  /*** Copy UserCVs to human readable CVs ***/
686  ksfse_flipexc = opuser0;
687 
688  ksfse_etlte = (int) opuser1;
689  if (ksfse_etlte != PSD_OFF && ksfse_etlte != PSD_ON) {
690  return ks_error("'ETL controls TE' flag must be either [0:OFF, 1:ON]"); /* User error */
691  }
692 
693  if (existcv(opetl)) {
694  /* if ETL has been selected, adjust TR menu to either T1-w or T2-w mode */
695  if (exist(opetl) < 6) {
696  pitrval3 = 450ms;
697  pitrval4 = 500ms;
698  pitrval5 = 550ms;
699  pitrval6 = 600ms;
700  } else {
701  pitrval3 = 2500ms;
702  pitrval4 = 3000ms;
703  pitrval5 = 4000ms;
704  pitrval6 = 5000ms;
705  }
706  }
707 
708  /* Inflow suppression (only if spacing or multiple acqs) */
709  if (existcv(opslquant) && (opslspace > 0.0 || avmaxacqs > 1)) {
710  ksfse_inflowsuppression = opuser2;
711  } else {
712  cvoverride(ksfse_inflowsuppression, 0, PSD_FIX_OFF, PSD_EXIST_ON);
713  }
714  if (ksfse_inflowsuppression > 0) {
715  cvdesc(opuser2, "In-flow suppression 0:OFF [1:ON]"); /* Highlight ON */
716  } else {
717  cvdesc(opuser2, "In-flow suppression [0:OFF] 1:ON"); /* Highlight OFF */
718  }
719 
720  /* Fast recovery / T1w optimization */
721  if (opuser3 > 0) {
723  } else if (opfr) {
725  } else {
726  ksfse_recovery = 0;
727  }
728 
729  /* Min/Max TR */
730  {
731  char tmpstr[100];
732  (ksfse_mintr) = RUP_GRD((int) opuser4 * 1000); /* in [us] */
733  (ksfse_maxtr) = RUP_GRD((int) opuser5 * 1000); /* in [us] */
734 
735  if (opflair == OPFLAIR_GROUP) {
736  /* T2FLAIR */
737  (ksinv_mintr_t2flair) = (ksfse_mintr > 0) ? ksfse_mintr : _ksinv_mintr_t2flair.defval;
738  if (ksfse_mintr > 0)
739  sprintf(tmpstr, "Min TR (ms) [0: Auto]");
740  else
741  sprintf(tmpstr, "Min TR (ms) [0: Auto (%d)]", _ksinv_mintr_t2flair.defval/1000);
742  cvdesc(opuser4, tmpstr);
743  } else if (opflair == OPFLAIR_INTERLEAVED) {
744  /* T1FLAIR */
745  (ksinv_mintr_t1flair) = (ksfse_mintr > 0) ? ksfse_mintr : _ksinv_mintr_t1flair.defval;
746  (ksinv_maxtr_t1flair) = (ksfse_maxtr > 0) ? ksfse_maxtr : _ksinv_maxtr_t1flair.defval;
747 
748  if (ksfse_mintr > 0)
749  sprintf(tmpstr, "Min TR (ms) [0: Auto]");
750  else
751  sprintf(tmpstr, "Min TR (ms) [0: Auto (%d)]", _ksinv_mintr_t1flair.defval/1000);
752  cvdesc(opuser4, tmpstr);
753 
754  if (ksfse_maxtr > 0)
755  sprintf(tmpstr, "Max TR (ms) [0: Auto]");
756  else
757  sprintf(tmpstr, "Max TR (ms) [0: Auto (%d)]", _ksinv_maxtr_t1flair.defval/1000);
758  cvdesc(opuser5, tmpstr);
759 
760  } else {
761  cvdesc(opuser4, _ksfse_mintr.descr);
762  cvdesc(opuser5, _ksfse_maxtr.descr);
763  }
764 }
765 
766  /* overall RF pulse stretching */
767  rf_stretch_all = opuser6;
768 
769 
770  /* Reserved opusers:
771  -----------------
772  ksfse_eval_inversion(): opuser26-29
773  GE reserves: opuser36-48 (epic.h)
774  */
775 
776  return SUCCESS;
777 
778 } /* ksfse_eval_UI() */
int ksfse_recovery
Definition: ksfse_implementation.e:101
int ksinv_mintr_t2flair
Definition: KSInversion.e:159
int ksinv_mintr_t1flair
Definition: KSInversion.e:160
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
float rf_stretch_all
Definition: ksfse_implementation.e:96
int ksfse_inflowsuppression
Definition: ksfse_implementation.e:85
float ksfse_flipexc
Definition: ksfse_implementation.e:82
int ksfse_maxtr
Definition: ksfse_implementation.e:132
STATUS ksfse_init_UI(void)
Initial setup of user interface (UI) with default values for menus and fields
Definition: ksfse_implementation.e:284
Definition: ksfse_implementation.e:41
int ksfse_mintr
Definition: ksfse_implementation.e:131
Definition: ksfse_implementation.e:41
int ksfse_etlte
Definition: ksfse_implementation.e:111
int ksinv_maxtr_t1flair
Definition: KSInversion.e:161

◆ ksfse_eval_esp()

int ksfse_eval_esp ( int *  min90_180,
int *  min180_echo,
int  slicecheck,
KSFSE_SEQUENCE seq 
)

Calculates echo spacing for the sequence

Parameters
[out]min90_180Pointer to the time between moment start of the excitation pulse to the center of the refocusing pulse in [us]
[out]min180_echoPointer to the time between center of the refocusing pulse to the center of the first echo in [us]
[in]slicecheck0: Normal mode 1: Slice check mode, where the readout is moved to the slice axis
[in]seqPointer to KSFSE_SEQUENCE
Return values
echospacingEcho Spacing in [us]
853  {
854  int echospacing;
855 
856  /*** minimum time needed between RF exc center to RF ref center ***/
857  /* latter portion of RF pulse incl ramptime of slice sel grad */
858  *min90_180 = seq->selrfexc.rf.iso2end;
859  if (slicecheck) {
860  /* need separate time for read dephaser */
861  *min90_180 += seq->selrfexc.grad.ramptime + seq->readdephaser.duration + seq->selrfexc.postgrad.duration +
863  } else {
864  /* max of seq->readdephaser and time from end of rfexc grad plateau to beginning of plateau for rfrefocus */
865  *min90_180 += IMax(2,
866  seq->readdephaser.duration /* X */,
868  }
869  *min90_180 += seq->selrfref1st.rf.start2iso; /* slice selection time until RF center */
870 
871  /*** minimum time needed between RF ref center and echo center ***/
872  *min180_echo = IMax(3, seq->selrfref1st.rf.iso2end, seq->selrfref2nd.rf.iso2end, seq->selrfref.rf.iso2end);
873  if (slicecheck) {
874  *min180_echo += IMax(4,
875  seq->phaseenc.grad.duration - seq->read.acqdelay + seq->read.time2center /* Y */,
876  seq->selrfref1st.grad.ramptime + seq->selrfref1st.postgrad.duration + seq->zphaseenc.grad.duration + seq->read.time2center /* Z 1st echo */,
877  (opetl > 1) * (seq->selrfref2nd.grad.ramptime + seq->selrfref2nd.postgrad.duration + seq->zphaseenc.grad.duration + seq->read.time2center) /* Z 2nd echo */,
878  (opetl > 2) * (seq->selrfref.grad.ramptime + seq->selrfref.postgrad.duration + seq->zphaseenc.grad.duration + seq->read.time2center) /* Z 3-Nth echo */);
879  } else {
880  *min180_echo += IMax(5,
881  seq->read.acqdelay /* X */,
882  seq->phaseenc.grad.duration /* Y */,
883  seq->selrfref1st.grad.ramptime + seq->selrfref1st.postgrad.duration + seq->zphaseenc.grad.duration /* Z 1st echo */,
884  (opetl > 1) * (seq->selrfref2nd.grad.ramptime + seq->selrfref2nd.postgrad.duration + seq->zphaseenc.grad.duration) /* Z 2nd echo */,
885  (opetl > 2) * (seq->selrfref.grad.ramptime + seq->selrfref.postgrad.duration + seq->zphaseenc.grad.duration) /* Z 3-Nth echo */);
886  *min180_echo += seq->read.time2center - seq->read.acqdelay; /* time from start of acquisition to k-space center */
887  }
888 
889  echospacing = IMax(2, *min90_180, *min180_echo) * 2;
890  echospacing = RUP_FACTOR(echospacing, 16);
891 
892  return echospacing;
893 }
KS_TRAP grad
Definition: KSFoundation.h:1491
int start2iso
Definition: KSFoundation.h:944
KS_TRAP grad
Definition: KSFoundation.h:1676
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
KS_READTRAP read
Definition: ksfse_implementation.e:51
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_TRAP readdephaser
Definition: ksfse_implementation.e:52
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
KS_TRAP postgrad
Definition: KSFoundation.h:1492
int iso2end
Definition: KSFoundation.h:945
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
int duration
Definition: KSFoundation.h:585
int time2center
Definition: KSFoundation.h:1585
int acqdelay
Definition: KSFoundation.h:1580
int ramptime
Definition: KSFoundation.h:583

◆ ksfse_eval_optimalkxnover()

int ksfse_eval_optimalkxnover ( KSFSE_SEQUENCE seq)

Calculates the optimal number of k-space points for partial kx Fourier that does not increase TE

This function plays by the following rules:

  1. CV ksfse_kxnover_min is the lowest number of samples allowed
  2. ksfse.read.res/2 is the highest number of samples allowed
  3. Increase kxnover until an increase in TE results, while staying within above limits
Parameters
[in]seqPointer to the KSFSE_SEQUENCE struct holding all sequence objects
Return values
kxnoverOptimal number of k-space points beyond half k-space for partial kx Fourier scans.
910  {
911 
912  int min90_180 = 0; /* [us] */
913  int min180_echo = 0; /* [us] */
914  int kxnover = 0; /* samples */
915 
916  ksfse_eval_esp(&min90_180, &min180_echo, ksfse_slicecheck, seq);
917 
918  if (seq->read.nover) {
919  /* we are currently using partial Fourier, adjust kxnover to balance the time before and after
920  the refocusing pulse */
921  kxnover = seq->read.nover + ((min90_180 - min180_echo) / ks_calc_bw2tsp(seq->read.acq.rbw));
922  } else {
923  /* we are currently using full Fourier (read.nover = 0) */
924  if (min90_180 > min180_echo) {
925  /* more time needed before the 180 anyway, no need to do partial Fourier */
926  kxnover = seq->read.res / 2;
927  } else {
928  kxnover = seq->read.res / 2 - ((min180_echo - min90_180) / ks_calc_bw2tsp(seq->read.acq.rbw));
929  }
930  }
931 
932  /* keep in range */
933  if (kxnover < ksfse_kxnover_min) {
934  kxnover = ksfse_kxnover_min;
935  } else if (kxnover > seq->read.res / 2) {
936  kxnover = seq->read.res / 2;
937  }
938 
939  kxnover = RUP_GRD(kxnover);
940 
941  return kxnover;
942 
943 } /* ksfse_eval_optimalkxnover() */
int ksfse_eval_esp(int *min90_180, int *min180_echo, int slicecheck, KSFSE_SEQUENCE *seq)
Calculates echo spacing for the sequence
Definition: ksfse_implementation.e:853
KS_READTRAP read
Definition: ksfse_implementation.e:51
float rbw
Definition: KSFoundation.h:734
int ksfse_kxnover_min
Definition: ksfse_implementation.e:107
int res
Definition: KSFoundation.h:1577
int ks_calc_bw2tsp(float bw)
Convert receiver bandwidth to dwell time
Definition: KSFoundation_host.c:4722
int nover
Definition: KSFoundation.h:1579
KS_READ acq
Definition: KSFoundation.h:1574
int ksfse_slicecheck
Definition: ksfse_implementation.e:94

◆ ksfse_eval_rfstretchfactor()

float ksfse_eval_rfstretchfactor ( float  patientweight,
float  flipangle,
int  tailoredrf_flag 
)
947  {
948  float rfstretchfactor = 1.0;
949  float flipangle_factor = 1.0;
950  float patientweight_factor = FMax(2, 1.0, patientweight * 0.0055 + 0.6); /* 1.0 at around 75 kg, never less than 0 */
951 
952  if (tailoredrf_flag) {
953  /* Empirical 2D plane as a function of patient weight and flip angle (for RF pulse set ref_fse1601/2/n)
954  Important to not let it below ~0.6 when flipangle or patient weight is too small */
955  flipangle_factor = FMax(2, 0.6, 0.0035 * flipangle + 0.15);
956  rfstretchfactor = flipangle_factor * patientweight_factor;
957  } else {
958  /* Empirical 2D plane as a function of patient weight and flip angle (for RF pulse set ref_se1b4)
959  Important to not let it below ~0.6 when flipangle or patient weight is too small */
960  flipangle_factor = FMax(2, 0.6, 0.0080 * flipangle - 0.10);
961  rfstretchfactor = flipangle_factor * patientweight_factor;
962  }
963 
964  if (rfstretchfactor < 0.6)
965  rfstretchfactor = 0.6; /* extra level of safety */
966 
967  return rfstretchfactor;
968 }

◆ ksfse_eval_setuprfpulses_2D()

STATUS ksfse_eval_setuprfpulses_2D ( KSFSE_SEQUENCE seq)

Sets up the RF objects for the ksfse sequence (2D)

This function attempts to mimick the RF scaling and flip angle varation performed in the product fsemaster.e psd, with and without the tailored RF (optlrdrf) option. It is called from ksfse_eval_setupobjects() to set up the RF pulses to keep ksfse_eval_setupobjects() from growing too much in size.

Parameters
[in]seqPointer to the KSFSE_SEQUENCE struct holding all sequence objects
Return values
STATUSSUCCESS or FAILURE
984  {
985  STATUS status;
986 
987  /* Clear potential gradient waveforms in the KS_SELRF objects before we choose our RF pulses */
992 
993  /*******************************************************************************************************
994  * RF Selections. Flip angle and slice thickness tweaks
995  *******************************************************************************************************/
996 
998 
999  if (optlrdrf == TRUE || opetl > 2) {
1000  seq->selrfexc.rf = exc_fse90; /* Excitation */
1001  seq->selrfref1st.rf = ref_fse1601; /* 1st Refocusing */
1002  seq->selrfref2nd.rf = ref_fse1602; /* 2nd Refocusing */
1003  seq->selrfref.rf = ref_fse160n; /* 3->ETL Refocusing */
1004  ksfse_gscalerfexc = 0.8;
1006  } else {
1007  seq->selrfexc.rf = exc_fl901mc;
1008  seq->selrfref1st.rf = ref_se1b4;
1009  seq->selrfref2nd.rf = ref_se1b4;
1010  seq->selrfref.rf = ref_se1b4;
1011  ksfse_gscalerfexc = 0.9;
1013  }
1014 
1015  /* Stretch factors for RF refocusing pulses */
1016  rf_stretch_rfref = ksfse_eval_rfstretchfactor(opweight, opflip, optlrdrf);
1018 
1019 #if EPIC_RELEASE >= 26
1020  if (opsarmode == 0) { /* normal mode */
1021  rf_stretch_all *= 1.6;
1022  } else if (opsarmode == 3) { /* low SAR mode */
1023  rf_stretch_all *= 3;
1024  }
1025 #endif
1026 
1027  /* Set flip angles */
1028  if (optlrdrf == TRUE && opetl > 2) {
1029  seq->selrfref1st.rf.flip = opflip + 0.6032 * (180.0 - opflip);
1030  seq->selrfref2nd.rf.flip = opflip + 0.1032 * (180.0 - opflip);
1031  seq->selrfref.rf.flip = opflip;
1032  } else {
1033  seq->selrfref1st.rf.flip = opflip;
1034  seq->selrfref2nd.rf.flip = opflip;
1035  seq->selrfref.rf.flip = opflip;
1036  }
1037 
1038 
1039  /*******************************************************************************************************
1040  * RF Excitation
1041  *******************************************************************************************************/
1043 
1044  /* Optional widening of the excitation pulse when we have slice gap or
1045  interleaved (opileave) slice mode where odd slices are completed and reconstructed
1046  before playing out the even slices */
1048  if (ksfse_inflowsuppression_mm <= 0) {
1049  /* ksfse_inflowsuppression_mm = 0 => auto thickness */
1050  int intleavefact = IMax(2, 1, avmaxacqs);
1051  float newthick = intleavefact * (ksfse_excthickness + opslspace);
1052  newthick = FMax(2, seq->selrfexc.slthick, newthick); /* to handle case where newthick is smaller */
1053  /* up to the case where newthick is three times the slice thickness */
1055  } else {
1056  /* ksfse_inflowsuppression_mm > 0: the user wants to specify how many mm extra the excitation
1057  thickness should be */
1059  }
1060  }
1061 
1062  seq->selrfexc.rf.flip = ksfse_flipexc; /* value from opuser0 */
1063 
1065  if (status != SUCCESS) return status;
1066 
1067  status = ks_eval_selrf(&seq->selrfexc, "rfexc");
1068  if (status != SUCCESS) return status;
1069 
1070  /*******************************************************************************************************
1071  * RF Refocusing (1st echo)
1072  *******************************************************************************************************/
1074 
1076  if (status != SUCCESS) return status;
1077 
1078  /* when quietness factor is used, find the crusherscale that minimizes the echo spacing (esp) */
1079  if (ks_qfact > 1) {
1080  int dummy1, dummy2;
1081  float c;
1082  float optc = 2.0;
1083  int optesp = 1s;
1084  int my_esp = KS_NOTSET;
1085  for (c = 0.0; c < 2.0; c += 0.01) {
1086  seq->selrfref1st.crusherscale = c;
1087  status = ks_eval_selrf(&seq->selrfref1st, "rfref1st");
1088  seq->selrfexc.postgrad.duration = 0; /* disable the rephaser of the excitation */
1089  seq->selrfref1st.pregrad.area += seq->selrfexc.postgrad.area; /* note: postgrad.area is negative ! */
1091  my_esp = ksfse_eval_esp(&dummy1, &dummy2, FALSE, seq);
1092  if (my_esp < optesp) {
1093  optesp = my_esp;
1094  optc = c;
1095  }
1096  }
1097  ksfse_crusherscale = optc;
1098  }
1099 
1101  status = ks_eval_selrf(&seq->selrfref1st, "rfref1st");
1102  if (status != SUCCESS) return status;
1103 
1104  seq->selrfexc.postgrad.duration = 0; /* disable the rephaser of the excitation */
1105  seq->selrfref1st.pregrad.area += seq->selrfexc.postgrad.area; /* note: postgrad.area is negative ! */
1107  if (status != SUCCESS) return status;
1108 
1109  /*******************************************************************************************************
1110  * RF Refocusing (2nd echo)
1111  *******************************************************************************************************/
1114 
1116  if (status != SUCCESS) return status;
1117 
1118  status = ks_eval_selrf(&seq->selrfref2nd, "rfref2nd");
1119  if (status != SUCCESS) return status;
1120 
1121  /*******************************************************************************************************
1122  * RF Refocusing (3rd-Nth echo)
1123  *******************************************************************************************************/
1126 
1128  if (status != SUCCESS) return status;
1129 
1130  status = ks_eval_selrf(&seq->selrfref, "rfref");
1131  if (status != SUCCESS) return status;
1132 
1133  return SUCCESS;
1134 
1135 } /* ksfse_eval_setuprfpulses_2D() */
float ksfse_inflowsuppression_mm
Definition: ksfse_implementation.e:86
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ks_eval_selrf(KS_SELRF *selrf, const char *const desc) WARN_UNUSED_RESULT
Sets up a KS_SELRF object for RF slice selection with preset gradient constraints
Definition: KSFoundation_host.c:3032
float ksfse_excthickness
Definition: ksfse_implementation.e:80
KS_WAVE gradwave
Definition: KSFoundation.h:1493
float ksfse_gscalerfexc
Definition: ksfse_implementation.e:81
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
int ksfse_eval_esp(int *min90_180, int *min180_echo, int slicecheck, KSFSE_SEQUENCE *seq)
Calculates echo spacing for the sequence
Definition: ksfse_implementation.e:853
float rf_stretch_all
Definition: ksfse_implementation.e:96
float flip
Definition: KSFoundation.h:940
int ksfse_inflowsuppression
Definition: ksfse_implementation.e:85
float ks_qfact
Definition: GERequired.e:243
KS_TRAP pregrad
Definition: KSFoundation.h:1490
DECL_TYPE KS_RF ref_fse160n
Definition: KSFoundation_GERF.c:113
float ksfse_flipexc
Definition: ksfse_implementation.e:82
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
float ksfse_gscalerfref
Definition: ksfse_implementation.e:93
STATUS ks_eval_trap(KS_TRAP *trap, const char *const desc) WARN_UNUSED_RESULT
Sets up a trapezoid using a KS_TRAP sequence object with preset gradient constraints
Definition: KSFoundation_host.c:434
DECL_TYPE KS_RF exc_fse90
Definition: KSFoundation_GERF.c:62
float area
Definition: KSFoundation.h:582
#define KSFSE_MAXTHICKFACT
Definition: ksfse_implementation.e:39
DECL_TYPE KS_RF ref_fse1602
Definition: KSFoundation_GERF.c:110
KS_TRAP postgrad
Definition: KSFoundation.h:1492
float rf_stretch_rfexc
Definition: ksfse_implementation.e:84
float ksfse_eval_rfstretchfactor(float patientweight, float flipangle, int tailoredrf_flag)
Definition: ksfse_implementation.e:947
KS_DESCRIPTION description
Definition: KSFoundation.h:580
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
DECL_TYPE KS_RF ref_se1b4
Definition: KSFoundation_GERF.c:104
DECL_TYPE KS_RF ref_fse1601
Definition: KSFoundation_GERF.c:107
float crusherscale
Definition: KSFoundation.h:1488
int duration
Definition: KSFoundation.h:585
float opslthick
STATUS ks_eval_stretch_rf(KS_RF *rf, float stretch_factor)
In-place stretching of a KS_RF object
Definition: KSFoundation_host.c:3500
uint8_t c[4]
Definition: KSFoundation_tgt.c:1388
void ks_init_wave(KS_WAVE *wave)
Resets a KS_WAVE sequence object to its default value (KS_INIT_WAVE)
Definition: KSFoundation_host.c:66
float ksfse_crusherscale
Definition: ksfse_implementation.e:92
float rf_stretch_rfref
Definition: ksfse_implementation.e:95
DECL_TYPE KS_RF exc_fl901mc
Definition: KSFoundation_GERF.c:59
float slthick
Definition: KSFoundation.h:1487

◆ ksfse_eval_setuprfpulses_3D()

STATUS ksfse_eval_setuprfpulses_3D ( KSFSE_SEQUENCE seq)

Sets up the RF objects for the ksfse sequence (3D)

This function attempts to mimick the RF scaling and flip angle varation performed in the product fsemaster.e psd, with and without the tailored RF (optlrdrf) option. It is called from ksfse_eval_setupobjects() to set up the RF pulses to keep ksfse_eval_setupobjects() from growing too much in size.

Parameters
[in]seqPointer to the KSFSE_SEQUENCE struct holding all sequence objects
Return values
STATUSSUCCESS or FAILURE
1153  {
1154  STATUS status;
1155 
1156  /* GE defines (epic.h) for opexcitemode:
1157  SELECTIVE 0, NON_SELECTIVE 1, FOCUS 2 */
1158  const float hardpulse_duration = 1ms;
1159  float adaptive_crusherscale = 1.0;
1160 
1161  /* Clear potential gradient waveforms in the KS_SELRF objects before we choose our RF pulses */
1166 
1167  cvoverride(opvthick, exist(opslquant) * exist(opslthick), _opslquant.fixedflag, existcv(opslquant));
1168  ksfse_excthickness = (exist(opslquant) - 2 * rhslblank) * exist(opslthick);
1169  ksfse_gscalerfexc = 1.0;
1170 
1172  return ks_error("%s: Call ks_eval_phaser(zphasenc) with .areaoffset = 0, before calling this function", __FUNCTION__);
1173  } else {
1174  /* we want the same big enough crusher for any kz encoding variation accross the ETL, where even the
1175  most negative kz encoding gradient will not be able to cancel out the positive crushers */
1176  adaptive_crusherscale = ksfse_crusherscale + (ksfse.zphaseenc.grad.area / KS_RF_STANDARD_CRUSHERAREA);
1177  }
1178 
1179 
1180  /*******************************************************************************************************
1181  * RF Excitation
1182  *******************************************************************************************************/
1183  if (opexcitemode == NON_SELECTIVE) {
1184  /* Non-selective 90 hard excitaion */
1185  status = ks_eval_rf_hard(&seq->selrfexc.rf, "rfexc", hardpulse_duration, 90);
1186  if (status != SUCCESS) return status;
1187  seq->selrfexc.rf.role = KS_RF_ROLE_EXC;
1188  } else {
1189  /* Selective 90 using a sharp high-BW minimum phase excitation pulse */
1190  seq->selrfexc.rf = exc_3dfgre;
1191  seq->selrfexc.rf.flip = 90.0;
1192  }
1193 
1194  seq->selrfexc.slthick = ksfse_excthickness / ksfse_gscalerfexc * (opexcitemode != NON_SELECTIVE);
1195 
1197  if (status != SUCCESS) return status;
1198 
1199  status = ks_eval_selrf(&seq->selrfexc, "rfexc");
1200  if (status != SUCCESS) return status;
1201 
1202  /*******************************************************************************************************
1203  * RF Refocusing (1st echo)
1204  *******************************************************************************************************/
1205  status = ks_eval_rf_hard(&seq->selrfref1st.rf, "rfref1st", hardpulse_duration, opflip);
1206  if (status != SUCCESS) return status;
1208 
1209  seq->selrfref1st.slthick = 0; /* N.B.: sel gradient = 0 if .selrfref1st.slthick = 0 (ks_eval_selrf()) */
1210 
1212  if (status != SUCCESS) return status;
1213 
1214  seq->selrfref1st.crusherscale = adaptive_crusherscale;
1215  status = ks_eval_selrf(&seq->selrfref1st, "rfref1st");
1216  if (status != SUCCESS) return status;
1217 
1218  /* Left crusher: Merge excitation rephaser into left crusher */
1219  /* N.B.: Right crusher will be embedded in zphasenc in ksfse_eval_setupobjects() */
1220  seq->selrfexc.postgrad.duration = 0; /* disable the rephaser of the excitation */
1221  seq->selrfref1st.pregrad.area += seq->selrfexc.postgrad.area; /* note: postgrad.area is negative ! */
1223  if (status != SUCCESS) return status;
1224 
1225 
1226  /*******************************************************************************************************
1227  * RF Refocusing (2nd echo)
1228  *******************************************************************************************************/
1229  seq->selrfref2nd.rf = seq->selrfref1st.rf;
1230  seq->selrfref2nd.slthick = seq->selrfref1st.slthick;
1232  status = ks_eval_selrf(&seq->selrfref2nd, "rfref2nd");
1233  if (status != SUCCESS) return status;
1234 
1235  /*******************************************************************************************************
1236  * RF Refocusing (3rd-Nth echo)
1237  *******************************************************************************************************/
1238  seq->selrfref.rf = seq->selrfref1st.rf;
1239  seq->selrfref.slthick = seq->selrfref1st.slthick;
1241  status = ks_eval_selrf(&seq->selrfref, "rfref");
1242  if (status != SUCCESS) return status;
1243 
1244 
1245  /*******************************************************************************************************
1246  * Move crushers area from selrf.pregrad/postgrad to zphasenc.areaoffset
1247  * Disable pre/postgrads by setting their duration to 0
1248  *******************************************************************************************************/
1249  seq->selrfref1st.postgrad.duration = 0; /* right crusher only */
1250  seq->selrfref2nd.pregrad.duration = 0;
1251  seq->selrfref2nd.postgrad.duration = 0;
1252  seq->selrfref.pregrad.duration = 0;
1253  seq->selrfref.postgrad.duration = 0;
1254 
1256  status = ks_eval_phaser(&ksfse.zphaseenc, "zphaseenc"); /* update zphaseenc, now with .areaoffset > 0 */
1257  if (status != SUCCESS) return status;
1258 
1259 
1260  return SUCCESS;
1261 
1262 } /* ksfse_eval_setuprfpulses_3D() */
#define KS_RF_STANDARD_CRUSHERAREA
Definition: KSFoundation.h:154
#define areSame(a, b)
Definition: KSFoundation.h:119
KS_TRAP grad
Definition: KSFoundation.h:1676
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
STATUS ks_eval_phaser(KS_PHASER *phaser, const char *const desc) WARN_UNUSED_RESULT
Sets up an acquisition window with a trapezoid with preset gradient constraints
Definition: KSFoundation_host.c:2073
int role
Definition: KSFoundation.h:939
STATUS ks_eval_selrf(KS_SELRF *selrf, const char *const desc) WARN_UNUSED_RESULT
Sets up a KS_SELRF object for RF slice selection with preset gradient constraints
Definition: KSFoundation_host.c:3032
float ksfse_excthickness
Definition: ksfse_implementation.e:80
KS_WAVE gradwave
Definition: KSFoundation.h:1493
float ksfse_gscalerfexc
Definition: ksfse_implementation.e:81
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
Definition: KSFoundation.h:1953
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
float areaoffset
Definition: KSFoundation.h:1683
Definition: KSFoundation.h:1953
float rf_stretch_all
Definition: ksfse_implementation.e:96
float flip
Definition: KSFoundation.h:940
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
DECL_TYPE KS_RF exc_3dfgre
Definition: KSFoundation_GERF.c:74
STATUS ks_eval_trap(KS_TRAP *trap, const char *const desc) WARN_UNUSED_RESULT
Sets up a trapezoid using a KS_TRAP sequence object with preset gradient constraints
Definition: KSFoundation_host.c:434
float area
Definition: KSFoundation.h:582
KS_TRAP postgrad
Definition: KSFoundation.h:1492
float rf_stretch_rfexc
Definition: ksfse_implementation.e:84
STATUS ks_eval_rf_hard(KS_RF *rf, const char *const desc, int duration, float flip) WARN_UNUSED_RESULT
Sets up a KS_RF object with a rectangular (hard) pulse of a given duration.
Definition: KSFoundation_host.c:2409
KS_DESCRIPTION description
Definition: KSFoundation.h:580
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
float crusherscale
Definition: KSFoundation.h:1488
int duration
Definition: KSFoundation.h:585
float opslthick
STATUS ks_eval_stretch_rf(KS_RF *rf, float stretch_factor)
In-place stretching of a KS_RF object
Definition: KSFoundation_host.c:3500
void ks_init_wave(KS_WAVE *wave)
Resets a KS_WAVE sequence object to its default value (KS_INIT_WAVE)
Definition: KSFoundation_host.c:66
float ksfse_crusherscale
Definition: ksfse_implementation.e:92
float rf_stretch_rfref
Definition: ksfse_implementation.e:95
float slthick
Definition: KSFoundation.h:1487

◆ ksfse_eval_setuprfpulses_recovery()

STATUS ksfse_eval_setuprfpulses_recovery ( KSFSE_SEQUENCE seq)
1266  {
1267  STATUS status;
1268 
1271 
1272  /*******************************************************************************************************
1273  * Post-ETL forced recovery: T1-w Optimization / T2 fast Recovery
1274  *******************************************************************************************************/
1275 
1276  /* Recovery "negative" excitation (selrfrecover) */
1277  seq->selrfrecover.rf = seq->selrfexc.rf; /* already potentially RF-stretched */
1278  seq->selrfrecover.slthick = seq->selrfexc.slthick;
1279 
1280  status = ks_eval_selrf(&seq->selrfrecover, "rfrecover");
1281  if (status != SUCCESS) return status;
1282 
1283  /* no postgrad by setting duration = 0 (or pregrad either since KS_RF_ROLE_EXC) */
1284  seq->selrfrecover.postgrad.duration = 0;
1285 
1286  /* Mirror RF wave using "-1" (negative stretch factor), will mirror the excitation RF pulse waveform */
1287  status = ks_eval_stretch_rf(&seq->selrfrecover.rf, -1);
1288  if (status != SUCCESS) return status;
1289 
1290 
1291  /* Recovery refocusing (selrfrecoverref). Use flip angle and design from 'selrfref.rf' but left crusher
1292  area from selrfref1st.pregrad.area */
1293  seq->selrfrecoverref.rf = seq->selrfref.rf;
1296  status = ks_eval_selrf(&seq->selrfrecoverref, "rfrecoverref");
1297  if (status != SUCCESS) return status;
1298 
1299  if (KS_3D_SELECTED) {
1300  seq->selrfrecoverref.pregrad.duration = 0; /* zphaseenc.areaoffset takes over */
1301  }
1302 
1305  if (status != SUCCESS) return status;
1306 
1307  return SUCCESS;
1308 
1309 }
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
STATUS ks_eval_selrf(KS_SELRF *selrf, const char *const desc) WARN_UNUSED_RESULT
Sets up a KS_SELRF object for RF slice selection with preset gradient constraints
Definition: KSFoundation_host.c:3032
KS_WAVE gradwave
Definition: KSFoundation.h:1493
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
STATUS ks_eval_trap(KS_TRAP *trap, const char *const desc) WARN_UNUSED_RESULT
Sets up a trapezoid using a KS_TRAP sequence object with preset gradient constraints
Definition: KSFoundation_host.c:434
float area
Definition: KSFoundation.h:582
KS_TRAP postgrad
Definition: KSFoundation.h:1492
KS_DESCRIPTION description
Definition: KSFoundation.h:580
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
float crusherscale
Definition: KSFoundation.h:1488
int duration
Definition: KSFoundation.h:585
STATUS ks_eval_stretch_rf(KS_RF *rf, float stretch_factor)
In-place stretching of a KS_RF object
Definition: KSFoundation_host.c:3500
void ks_init_wave(KS_WAVE *wave)
Resets a KS_WAVE sequence object to its default value (KS_INIT_WAVE)
Definition: KSFoundation_host.c:66
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60
float slthick
Definition: KSFoundation.h:1487

◆ ksfse_eval_ssitime()

int ksfse_eval_ssitime ( )

Set the SSI time for the sequence

Return values
intSSI time in [us]
1318  {
1319 
1320  /* SSI time CV:
1321  Empirical finding as a function of etl on how much SSI time we need to update.
1322  But, use a longer SSI time when we write out data to file in scan() */
1323  ksfse_ssi_time = RUP_GRD(IMax(2, KSFSE_MIN_SSI_TIME + 13 * opetl, _ksfse_ssi_time.minval));
1324 
1325  /* Copy SSI CV to seqctrl field used by setssitime() */
1327 
1328  /* SSI time one-sequence-off workaround:
1329  We set the hardware ssitime in ks_scan_playsequence(), but it acts on the next sequence module, hence
1330  we aren't doing this correctly when using multiple sequence modules (as KSChemSat etc).
1331  One option would be to add a short dummy sequence ks_scan_playsequence(), but need to investigate
1332  if there is a better way. For now, let's assume the the necessary update time is the longest for
1333  the main sequence (this function), and let the ssi time for all other sequence modules (KSChemSat etc)
1334  have the same ssi time as the main sequence. */
1339 
1340  return ksfse_ssi_time;
1341 
1342 } /* ksfse_eval_ssitime() */
int ksfse_ssi_time
Definition: ksfse_implementation.e:126
int ksspsat_ssi_time
Definition: KSSpSat.e:135
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int kschemsat_ssi_time
Definition: KSChemSat.e:106
int ksinv_filltr_ssi_time
Definition: KSInversion.e:158
#define KSFSE_MIN_SSI_TIME
Definition: ksfse_implementation.e:38
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
int ssi_time
Definition: KSFoundation.h:1134
int ksinv_ssi_time
Definition: KSInversion.e:157

◆ ksfse_eval_setupobjects()

STATUS ksfse_eval_setupobjects ( )

Sets up all sequence objects for the main sequence module (KSFSE_SEQUENCE ksfse)

Return values
STATUSSUCCESS or FAILURE
1352  {
1353  STATUS status;
1354 
1355  /* Readout gradient and data acquisition */
1356  ksfse.read.fov = opfov;
1357  ksfse.read.res = RUP_FACTOR(opxres, 2); /* Round UP to nearest multiple of 2 */
1358 
1360  if (ksfse.read.rampsampling)
1361  ksfse.read.acqdelay = 16; /* us on the ramp until acq should begin */
1362  if (opautote == PSD_MINTE) { /* PSD_MINTE = 2 */
1363  ksfse_kxnover = ksfse_eval_optimalkxnover(&ksfse); /* Partial Fourier */
1365  } else {
1366  ksfse.read.nover = 0; /* Full Fourier */
1367  }
1368  ksfse.read.acq.rbw = oprbw;
1370  if (ks_eval_readtrap(&ksfse.read, "read") == FAILURE)
1371  return FAILURE;
1372 
1373  /* read dephaser */
1375  if (ks_eval_trap(&ksfse.readdephaser, "readdephaser") == FAILURE)
1376  return FAILURE;
1377 
1378  /* phase encoding gradient */
1379  ksfse.phaseenc.fov = opfov * opphasefov;
1380  ksfse.phaseenc.res = RUP_FACTOR((int) (opyres * opphasefov), 2); /* round up (RUP) to nearest multiple of 2 */
1381 
1382  if (ksfse.read.nover == 0 && opnex < 1) {
1383  int kynover;
1384  kynover = ksfse.phaseenc.res * (opnex - 0.5);
1385  kynover = ((kynover + 1) / 2) * 2; /* round to nearest even number */
1386  if (kynover < KSFSE_MINHNOVER)
1387  kynover = KSFSE_MINHNOVER; /* protect against too few overscans */
1388  ksfse.phaseenc.nover = IMin(2, kynover, ksfse.phaseenc.res / 2);
1389  } else {
1390  ksfse.phaseenc.nover = 0;
1391  }
1392 
1393  /* set .R and .nacslines fields of ksfse.phaseenc using ks_eval_phaser_setaccel() before calling ks_eval_phaser() */
1394  if (opasset) {
1395  cvoverride(ksfse_minacslines, 0, PSD_FIX_OFF, PSD_EXIST_ON);
1396  } else if (oparc) {
1397  ksfse_minacslines = _ksfse_minacslines.defval;
1398  }
1399  if (ks_eval_phaser_setaccel(&ksfse.phaseenc, ksfse_minacslines, opaccel_ph_stride) == FAILURE)
1400  return FAILURE;
1401 
1402  if (ks_eval_phaser(&ksfse.phaseenc, "phaseenc") == FAILURE)
1403  return FAILURE;
1404 
1405 
1406  /* z phase encoding gradient (N.B. 3D is not yet implemented in this sequence) */
1407  if (KS_3D_SELECTED) { /* PSD_3D or PSD_3DM */
1408 
1409  ksfse.selrfref1st.postgrad.duration = 0; /* disable the right crusher gradient (.duration = 0), and put area necessary in zphaseenc.areaoffset */
1410  ksfse.zphaseenc.areaoffset = 0; /* explicitly 0 here, since modified later in ksfse_eval_setuprfpulses_3D() */
1411  ksfse.zphaseenc.fov = opvthick;
1412  ksfse.zphaseenc.res = IMax(2, 1, opslquant);
1413  ksfse.zphaseenc.nover = 0;
1414 
1415  /* set .R and .nacslines fields of ksfse.zphaseenc using ks_eval_phaser_setaccel() before calling ks_eval_phaser() */
1416  if (opasset) {
1417  cvoverride(ksfse_minzacslines, 0, PSD_FIX_OFF, PSD_EXIST_ON);
1418  } else if (oparc) {
1419  ksfse_minzacslines = _ksfse_minzacslines.defval;
1420  }
1421  if (ks_eval_phaser_setaccel(&ksfse.zphaseenc, ksfse_minzacslines, opaccel_sl_stride) == FAILURE)
1422  return FAILURE;
1423 
1424  /* another call done in ksfse_eval_setuprfpulses_3D() with .areaoffset > 0 */
1425  if (ks_eval_phaser(&ksfse.zphaseenc, "zphaseenc") == FAILURE)
1426  return FAILURE;
1427 
1428  } else {
1429 
1431 
1432  }
1433 
1434 
1435  /* setup RF pulses in FSE train */
1436  if (KS_3D_SELECTED) {
1437  if (ksfse_eval_setuprfpulses_3D(&ksfse) == FAILURE)
1438  return FAILURE;
1439  } else {
1440  if (ksfse_eval_setuprfpulses_2D(&ksfse) == FAILURE)
1441  return FAILURE;
1442  }
1443 
1444  /* Add recovery pulses after the main Echo Train, common for 2D and 3D */
1445  if (ksfse_recovery) {
1447  if (status != SUCCESS) return status;
1448  } else {
1451  }
1452 
1453  /* post-read spoiler */
1455  if (ks_eval_trap(&ksfse.spoiler, "spoiler") == FAILURE)
1456  return FAILURE;
1457 
1458  /* init seqctrl */
1460  strcpy(ksfse.seqctrl.description, "ksfsemain");
1462 
1463  return SUCCESS;
1464 
1465 } /* ksfse_eval_setupobjects() */
int ksfse_recovery
Definition: ksfse_implementation.e:101
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
int ksfse_eval_ssitime()
Set the SSI time for the sequence
Definition: ksfse_implementation.e:1318
int ksfse_eval_optimalkxnover(KSFSE_SEQUENCE *seq)
Calculates the optimal number of k-space points for partial kx Fourier that does not increase TE...
Definition: ksfse_implementation.e:910
int res
Definition: KSFoundation.h:1678
int opxres
int opyres
KS_TRAP spoiler
Definition: ksfse_implementation.e:55
STATUS ks_eval_phaser(KS_PHASER *phaser, const char *const desc) WARN_UNUSED_RESULT
Sets up an acquisition window with a trapezoid with preset gradient constraints
Definition: KSFoundation_host.c:2073
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
int ksfse_kxnover
Definition: ksfse_implementation.e:108
float fov
Definition: KSFoundation.h:1576
STATUS ksfse_eval_setuprfpulses_recovery(KSFSE_SEQUENCE *seq)
Definition: ksfse_implementation.e:1266
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
STATUS ksfse_eval_setuprfpulses_3D(KSFSE_SEQUENCE *seq)
Sets up the RF objects for the ksfse sequence (3D)
Definition: ksfse_implementation.e:1153
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
KS_READTRAP read
Definition: ksfse_implementation.e:51
int ksfse_minzacslines
Definition: ksfse_implementation.e:120
float areaoffset
Definition: KSFoundation.h:1683
float rbw
Definition: KSFoundation.h:734
float paddingarea
Definition: KSFoundation.h:1581
STATUS ks_eval_phaser_setaccel(KS_PHASER *phaser, int min_acslines, float R) WARN_UNUSED_RESULT
Definition: KSFoundation_host.c:1995
#define KSFSE_MINHNOVER
Definition: ksfse_implementation.e:37
KS_TRAP readdephaser
Definition: ksfse_implementation.e:52
void ks_init_seqcontrol(KS_SEQ_CONTROL *seqcontrol)
Resets KS_SEQ_CONTROL to its default value (KS_INIT_SEQ_CONTROL)
Definition: KSFoundation_host.c:112
int res
Definition: KSFoundation.h:1577
int ksfse_minacslines
Definition: ksfse_implementation.e:119
float opfov
STATUS ks_eval_trap(KS_TRAP *trap, const char *const desc) WARN_UNUSED_RESULT
Sets up a trapezoid using a KS_TRAP sequence object with preset gradient constraints
Definition: KSFoundation_host.c:434
void ks_init_selrf(KS_SELRF *selrf)
Resets a KS_SELRF sequence object to its default value (KS_INIT_SELRF)
Definition: KSFoundation_host.c:78
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
float area
Definition: KSFoundation.h:582
KS_TRAP postgrad
Definition: KSFoundation.h:1492
int nover
Definition: KSFoundation.h:1679
STATUS ksfse_eval_setuprfpulses_2D(KSFSE_SEQUENCE *seq)
Sets up the RF objects for the ksfse sequence (2D)
Definition: ksfse_implementation.e:984
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
int ksfse_rampsampling
Definition: ksfse_implementation.e:109
STATUS ks_eval_readtrap(KS_READTRAP *readtrap, const char *const desc) WARN_UNUSED_RESULT
Sets up an acquisition window with a trapezoid with preset gradient constraints
Definition: KSFoundation_host.c:733
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
int nover
Definition: KSFoundation.h:1579
int rampsampling
Definition: KSFoundation.h:1578
KS_READ acq
Definition: KSFoundation.h:1574
int duration
Definition: KSFoundation.h:585
float area2center
Definition: KSFoundation.h:1584
float fov
Definition: KSFoundation.h:1677
int acqdelay
Definition: KSFoundation.h:1580
void ks_init_phaser(KS_PHASER *phaser)
Resets a KS_PHASER sequence object to its default value (KS_INIT_PHASER)
Definition: KSFoundation_host.c:86
float ksfse_spoilerarea
Definition: ksfse_implementation.e:83
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60
float ksfse_xcrusherarea
Definition: ksfse_implementation.e:112

◆ ksfse_eval_TErange()

STATUS ksfse_eval_TErange ( )

Sets the min/max TE and echo spacing for the FSE train based on rBW, res and ETL

Based on the duration of the sequence objects involved, this function first calculates the minimum echo spacing in the FSE train (ksfse_esp). Then, if the SSFSE flag is set (opssfse), the ETL (opetl) is forced to be equal to the number of phase encoding lines acquired (see ks_eval_phaseviewtable()), otherwise the chosen ETL is used to calculate how many TRs (or shots) is necessary to fill k-space (ksfse.phaseenc_plan.num_shots). This value is used later in scan.

Next, if the user has selected that the "ETL should set TE" (ksfse_etlte = TRUE), the echo time is forced to be equal to the most optimal one in the center of the echo train (optecho). The benefits of setting ksfse_etlte are a) reduced T2-blurring due to faster k-space traversal, and b) no FSE ghosting. The drawback is that TE needs to be controlled via changing ETL in the UI, but image quality wise, it may still be worth it. If ksfse_etlte = FALSE, ksfse_calc_echo() will find the bestecho, which is the echo index in the FSE train closest to the desired TE. When bestecho ends up being equal to optecho (as enforced by ksfse_etlte), the image quality improves, however this it not possible, especially for long ETLs with a normal TE of 80-100 ms.

Last, this function calls ksfse_eval_TEmenu() to change the TE menu so the optimal TE is always at the top, followed by other TEs one or more echo spacings from the optimal TE.

N.B.: ksfse_esp is the shortest time allowed between the RF excitation and the first echo, which is also the same time needed between two consecutive echoes in the FSE train. ksfse_esp is used in ksfse_pg(). If the pulse sequence design changes in ksfse_pg() such that more/less time is needed to the first echo, or between consecutive echoes, ksfse_esp must here be updated to avoid gradient overlaps.

Return values
STATUSSUCCESS or FAILURE
1500  {
1501  int min90_180 = 0;
1502  int min180_echo = 0;
1503  double optecho, bestecho;
1504  int fixed_teflag = _opte.fixedflag;
1505  int exist_teflag = _opte.existflag;
1506  STATUS status;
1507 
1508 
1509  /* echo spacing (esp) */
1510  ksfse_esp = ksfse_eval_esp(&min90_180, &min180_echo, ksfse_slicecheck, &ksfse);
1511 
1512  /* ETL */
1513  if (opssfse == PSD_ON) {
1514  /* SSFSE case */
1515  cvoverride(opetl, ksfse.phaseenc.numlinestoacq, PSD_FIX_ON, PSD_EXIST_ON);
1516  } else {
1517  if (opetl < 1) {
1518  cvoverride(opetl, 1, PSD_FIX_ON, PSD_EXIST_ON);
1519  } else if (opetl > ksfse.phaseenc.numlinestoacq) {
1520  return ks_error("ksfse_eval_TErange: Please reduce ETL to %d", ksfse.phaseenc.numlinestoacq);
1521  }
1522  }
1523 
1524  /* if single shot (2D), ks_phaseencoding_generate_2Dfse() will not allow non-optimal TE, i.e. linear k-space sweep
1525  is required. Therefore, ETL must control TE via setting ksfse_etlte = TRUE */
1526  if (CEIL_DIV(ksfse.phaseenc.numlinestoacq, opetl) == 1) {
1527  cvoverride(ksfse_etlte, TRUE, PSD_FIX_ON, PSD_EXIST_ON);
1528  } else {
1529  _ksfse_etlte.fixedflag = FALSE;
1530  }
1531 
1532 
1533  /* calc spacing between RF pulses used for T1-w opt. */
1534  if (ksfse_recovery) {
1535 
1536  int recovery_min_read2ref = (ksfse.read.grad.duration - ksfse.read.time2center - ksfse.read.acqdelay) +
1540 
1541  int recovery_min_ref2exc = ksfse.selrfrecoverref.rf.iso2end +
1542  IMax(2, ksfse.readdephaser.duration,
1546 
1547  if (ksfse_slicecheck) {
1548  recovery_min_read2ref += ksfse.read.grad.ramptime;
1549  recovery_min_ref2exc = ksfse.selrfrecoverref.rf.iso2end +
1555  }
1556 
1557  int ksfse_recovery_spacing = IMax(2, recovery_min_read2ref, recovery_min_ref2exc) * 2;
1558 
1559  ksfse_esp = IMax(2, ksfse_esp, ksfse_recovery_spacing);
1560  }
1561 
1562  ksfse_esp += GRAD_UPDATE_TIME * 2; /* 8us extra margin */
1563  ksfse_esp = RUP_FACTOR(ksfse_esp, 8); /* make sure ksfse_esp is divisible by 8us (as we will need to use ksfse_esp/2 on 4us grid) */
1564 
1565 
1566  /* protect against too long sequence before we are having trouble in pg */
1567  if (ksfse_esp * opetl > 2s) {
1568  return ks_error("%s: Too long sequence duration (%.1f ms)", __FUNCTION__, (ksfse_esp * opetl) / 1000.0);
1569  }
1570 
1571  /* bestecho: opte rounded off. optecho: ignores 'opte' input */
1572  int dummy;
1573  status = ks_fse_calcecho(&bestecho, &optecho, &dummy, &ksfse.phaseenc, KS_PF_EARLY_TE, opte, opetl, ksfse_esp);
1574  if (status != SUCCESS) return status;
1575 
1576  setpopup(opte, PSD_OFF);
1577 
1578 
1579  if (ksfse_etlte) {
1580  /* ETL is controlling the use of an optimal TE to ensure a linear k-space sweep */
1581  cvoverride(opte, (int) (ksfse_esp * optecho), PSD_FIX_ON, PSD_EXIST_ON);
1582  pite1nub = 0;
1583  _opte.defval = opte;
1584  pite1val2 = opte;
1585  avminte = opte;
1586  avmaxte = opte;
1587 
1588  /* must set opautote here so that the TE menu is shaded rather than removed */
1589  cvoverride(opautote, PSD_MINTEFULL, PSD_FIX_OFF, PSD_EXIST_ON);
1590 
1591  } else {
1592 
1593  /* minimum TE */
1594  avminte = ksfse_esp;
1595 
1596  if (opautote || (opte < avminte)) {
1597  cvoverride(opte, avminte, PSD_FIX_ON, PSD_EXIST_ON);
1598  } else {
1599  /* round opte to nearest valid value */
1600  cvoverride(opte, (int) (ksfse_esp * bestecho), fixed_teflag, exist_teflag);
1601  }
1602 
1603  /* maximum TE */
1604  avmaxte = ksfse_esp * opetl;
1605 
1606  /* Setup TE menu */
1607  ksfse_eval_TEmenu(ksfse_esp, avmaxte, opetl, optecho);
1608 
1609  }
1610 
1611 
1612  { /* Update opuser1 to show optimal TE and echo spacing) */
1613  char tmpstr[100];
1614  sprintf(tmpstr, "%s [opt=%.1f, esp=%d]", _ksfse_etlte.descr, (ksfse_esp * optecho) / 1000.0, ksfse_esp / 1000);
1615  cvdesc(opuser1, tmpstr);
1616  }
1617 
1618  return SUCCESS;
1619 
1620 } /* ksfse_eval_TErange() */
STATUS ks_fse_calcecho(double *bestecho, double *optecho, int *nacqlines_to_kspacecenter, KS_PHASER *pe, ks_enum_pf_earlylate_te pf_direction, int TE, int etl, int esp)
Calculates the ETL index corresponding the desired TE given a KS_PHASER object and echo spacing...
Definition: KSFoundation_common.c:580
int ksfse_recovery
Definition: ksfse_implementation.e:101
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
KS_TRAP grad
Definition: KSFoundation.h:1491
int start2iso
Definition: KSFoundation.h:944
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int numlinestoacq
Definition: KSFoundation.h:1684
int ksfse_eval_esp(int *min90_180, int *min180_echo, int slicecheck, KSFSE_SEQUENCE *seq)
Calculates echo spacing for the sequence
Definition: ksfse_implementation.e:853
KS_READTRAP read
Definition: ksfse_implementation.e:51
KS_TRAP grad
Definition: KSFoundation.h:1586
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_TRAP readdephaser
Definition: ksfse_implementation.e:52
KS_RF rf
Definition: KSFoundation.h:1485
KS_TRAP postgrad
Definition: KSFoundation.h:1492
int iso2end
Definition: KSFoundation.h:945
int ksfse_esp
Definition: ksfse_implementation.e:113
int duration
Definition: KSFoundation.h:585
void ksfse_eval_TEmenu(int esp, int maxte, int etl, double optechono)
Sets up the TE menu based on echo spacing, max TE, ETL and the optimal echo index
Definition: ksfse_implementation.e:802
int time2center
Definition: KSFoundation.h:1585
int ksfse_etlte
Definition: ksfse_implementation.e:111
int acqdelay
Definition: KSFoundation.h:1580
int ramptime
Definition: KSFoundation.h:583
Definition: KSFoundation.h:1899
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60
int ksfse_slicecheck
Definition: ksfse_implementation.e:94

◆ ksfse_eval_inversion()

STATUS ksfse_eval_inversion ( KS_SEQ_COLLECTION seqcollection)

Wrapper function to KSInversion functions to add single and dual IR support to this sequence

It is important that ksfse_eval_inversion() is called after other sequence modules have been set up and added to the KS_SEQ_COLLECTION struct in my_cveval(). Otherwise the TI and TR timing will be wrong.

Whether IR is on or off is determined by ksinv1_mode, which is set up in KSINV_EVAL()->ksinv_eval(). If it is off, this function will return quietly.

This function calls ksinv_eval_multislice() (KSInversion.e), which takes over the responsibility of TR timing that otherwise is determined in ksfse_eval_tr(). ksinv_eval_multislice() sets seqcollection.evaltrdone = TRUE, which indicates that TR timing has been done. ksfse_eval_tr() checks whether seqcollection.evaltrdone = TRUE to avoid that non-inversion TR timing overrides the TR timing set up in ksinv_eval_multislice().

At the end of this function, TR validation and heat/SAR checks are done.

Parameters
[in]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
Return values
STATUSSUCCESS or FAILURE
1646  {
1647  STATUS status;
1648  int slperpass, npasses;
1649  int approved_TR = FALSE;
1650 
1651  status = KSINV_EVAL(seqcollection, 26, 27, 28, 29); /* args 2-6: integer X corresponds to opuserX CV */
1652  if (status != SUCCESS) return status;
1653 
1654  if (((int) *ksinv1_mode) == KSINV_OFF) {
1655  /* If no IR1 flag on, return */
1656  return SUCCESS;
1657  }
1658 
1659  if (KS_3D_SELECTED) {
1660  return ks_error("%s: This function is only for 2D scans", __FUNCTION__);
1661  }
1662 
1663  /* interleaved slices in slice gap menu, force 2+ acqs */
1664  if (opileave)
1665  npasses = 2;
1666  else
1667  npasses = 1;
1668 
1669 
1670  while (approved_TR == FALSE) {
1671 
1672  /* Inversion (specific to 2D FSE/EPI type of PSDs). Must be done after all other sequence modules have been set up */
1673  slperpass = CEIL_DIV((int) exist(opslquant), npasses);
1674 
1675  status = ks_calc_sliceplan(&ks_slice_plan, exist(opslquant), slperpass);
1676  if (status != SUCCESS) return status;
1677 
1678  /* ksinv_eval_multislice() sets seqcollection.evaltrdone = TRUE. This indicates that TR timing has been done.
1679  ksfse_eval_tr() check whether seqcollection.evaltrdone = TRUE to avoid that non-inversion TR timing overrides the
1680  intricate TR timing with inversion module(s). At the end of ksinv_eval_multislice(), TR validation and heat/SAR checks are done */
1682  if (status != SUCCESS) return status;
1683 
1684  if (existcv(optr) && existcv(opslquant) && opflair == OPFLAIR_INTERLEAVED && optr > ksinv_maxtr_t1flair) {
1685  /* T1-FLAIR, too long TR */
1686  if (npasses > exist(opslquant)) {
1687  return ks_error("%s: T1-FLAIR: TR not met for single slice per TR", __FUNCTION__);
1688  }
1689  npasses++; /* increase #passes and call ksinv_eval_multislice() again with a new ks_slice_plan */
1690  } else if (existcv(optr) && existcv(opslquant) && opflair == OPFLAIR_INTERLEAVED && optr < ksinv_mintr_t1flair) {
1691  /* T1-FLAIR, too short TR */
1692  return ks_error("%s: T1-FLAIR: Min TR is %.0f ms. Increase slices or ETL", __FUNCTION__, ksinv_mintr_t1flair/1000.0);
1693  } else {
1694  /* non-T1-FLAIR, or T1-FLAIR with approved TR value */
1695  approved_TR = TRUE;
1696  }
1697 
1698  } /* while (approved_TR == FALSE) */
1699 
1700 
1701  return SUCCESS;
1702 
1703 } /* ksfse_eval_inversion() */
int ksinv_mintr_t1flair
Definition: KSInversion.e:160
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
float * ksinv1_mode
Definition: KSInversion.e:140
int ksfse_scan_coreslice_nargs(const SCAN_INFO *slice_pos, int dabslice, int nargs, void **args)
Wrapper function to ksfse_scan_coreslice() with standardized input arguments
Definition: ksfse_implementation.e:2618
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
STATUS ks_calc_sliceplan(KS_SLICE_PLAN *slice_plan, int nslices, int slperpass)
Calculates the data acquisition order for a standard interleaved 2D scans using one or more passes...
Definition: KSFoundation_host.c:4866
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
#define KSINV_EVAL(sptr, o1, o2, o3, o4)
C-macro assigning four UserCV slots and then calling ksinv_eval()
Definition: KSInversion.e:1131
Definition: KSInversion.e:45
int ksinv_maxtr_t1flair
Definition: KSInversion.e:161
STATUS ksinv_eval_multislice(KS_SEQ_COLLECTION *seqcollection, KS_SLICE_PLAN *slice_plan, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args, KS_SEQ_CONTROL *mainseqctrl)
Calculates the duration of inversion module(s) for various inversion modes
Definition: KSInversion.e:1516

◆ ksfse_eval_tr()

STATUS ksfse_eval_tr ( KS_SEQ_COLLECTION seqcollection)

Evaluation of number of slices / TR, set up of slice plan, TR validation and SAR checks

With the current sequence collection (see my_cveval()), and a function pointer to an argument-standardized wrapper function (ksfse_scan_sliceloop_nargs()) to the slice loop function (ksfse_scan_sliceloop(), this function calls GEReq_eval_TR(), where number of slices that can fit within one TR is determined by adding more slices as input argument to the slice loop function. For more details see GEReq_eval_TR().

With the number of slices/TR now known, a standard 2D slice plan is set up using ks_calc_sliceplan() and the duration of the main sequence is increased based on timetoadd_perTR, which was returned by GEReq_eval_TR(). timetoadd_perTR > 0 when optr > avmintr and when heat or SAR restrictions requires avmintr to be larger than the net sum of sequence modules in the slice loop.

This function first checks whether seqcollection.evaltrdone == TRUE. This is e.g. the case for inversion where the TR timing instead is controlled using ksfse_eval_inversion() (calling ksinv_eval_multislice()).

At the end of this function, TR validation and heat/SAR checks are done using GEReq_eval_checkTR_SAR().

Parameters
[in]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
Return values
STATUSSUCCESS or FAILURE
1730  {
1731  int timetoadd_perTR;
1732  STATUS status;
1733  int slperpass, min_npasses;
1734 
1735  if (seqcollection->evaltrdone == TRUE) {
1736  /*
1737  We cannot call GEReq_eval_TR() or GEReq_eval_checkTR_SAR(..., ksfse_scan_sliceloop_nargs, ...) if e.g. the inversion sequence module is used. This is because
1738  ksinv_scan_sliceloop() is used instead of ksfse_scan_sliceloop(). When ksinv1.params.mode != 0 (i.e. inversion sequence module on), the TR timing and
1739  heat/SAR limits checks are done in ksinv_eval_multislice(), which is called from ksfse_eval_inversion().
1740  In the future, other sequence modules may want to take over the responsibility of TR calculations and SAR checks, in which case they need to end their corresponding function
1741  by setting evaltrdone = TRUE to avoid double processing here */
1742  return SUCCESS;
1743  }
1744 
1745  /* interleaved slices in slice gap menu, force 2+ acqs */
1746  if (opileave)
1747  min_npasses = 2;
1748  else
1749  min_npasses = 1;
1750 
1751  /* Calculate # slices per TR and how much spare time we have within the current TR by running the slice loop. */
1752  status = GEReq_eval_TRrange(&slperpass, &timetoadd_perTR, min_npasses, ksfse_mintr, ksfse_maxtr, seqcollection, ksfse_scan_sliceloop_nargs, 0, NULL);
1753  if (status != SUCCESS) return status;
1754 
1755  /* Calculate the slice plan (ordering) and passes (acqs). ks_slice_plan is passed to GEReq_predownload_store_sliceplan() in predownload() */
1756  if (KS_3D_SELECTED) {
1757  ks_calc_sliceplan(&ks_slice_plan, exist(opvquant), 1 /* seq 3DMS */);
1758  } else {
1759  ks_calc_sliceplan(&ks_slice_plan, exist(opslquant), slperpass);
1760  }
1761 
1762  /* We spread the available timetoadd_perTR evenly, by increasing the .duration of each slice by timetoadd_perTR/ks_slice_plan.nslices_per_pass */
1763  ksfse.seqctrl.duration = RUP_GRD(ksfse.seqctrl.duration + CEIL_DIV(timetoadd_perTR, ks_slice_plan.nslices_per_pass));
1764 
1765  /* Update SAR values in the UI (error will occur if the sum of sequence durations differs from optr) */
1767  if (status != SUCCESS) return status;
1768 
1769 
1770  /* Fill in the 'tmin' and 'tmin_total'. tmin_total is only like GEs use of the variable when TR = minTR */
1771  tmin = ksfse.seqctrl.min_duration;
1772  tmin_total = ksfse.seqctrl.duration;
1773 
1774  return SUCCESS;
1775 
1776 } /* ksfse_eval_tr() */
STATUS GEReq_eval_checkTR_SAR(KS_SEQ_COLLECTION *seqcollection, int nslices, int(*play_loop)(int, int, void **), int nargs, void **args)
Runs the slice loop and validates TR and SAR/hardware limits
Definition: GERequired.e:963
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
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int duration
Definition: KSFoundation.h:1135
int ksfse_scan_sliceloop_nargs(int slperpass, int nargs, void **args)
Wrapper function to ksfse_scan_sliceloop() with standardized input arguments
Definition: ksfse_implementation.e:2713
int nslices_per_pass
Definition: KSFoundation.h:1353
int min_duration
Definition: KSFoundation.h:1132
int ksfse_maxtr
Definition: ksfse_implementation.e:132
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
int evaltrdone
Definition: KSFoundation.h:1303
STATUS ks_calc_sliceplan(KS_SLICE_PLAN *slice_plan, int nslices, int slperpass)
Calculates the data acquisition order for a standard interleaved 2D scans using one or more passes...
Definition: KSFoundation_host.c:4866
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
int ksfse_mintr
Definition: ksfse_implementation.e:131

◆ ksfse_eval_scantime()

STATUS ksfse_eval_scantime ( )

Set the number of dummy scans for the sequence and calls ksfse_scan_scanloop() to determine

the length of the scan

After setting the number of dummy scans based on the current TR, the ksfse_scan_scanloop() is called to get the scan time. pitscan is the UI variable for the scan clock shown in the top right corner on the MR scanner.

Return values
STATUSSUCCESS or FAILURE
1792  {
1793 
1794  if (optr > 6s || opetl == ksfse.phaseenc.numlinestoacq) {
1795  /* For long TRs or single-shot FSE, don't use dummies */
1796  ksfse_dda = 0;
1797  } else if (optr > 2s) {
1798  /* For medium long TRs */
1799  ksfse_dda = 1;
1800  } else {
1801  ksfse_dda = 2;
1802  }
1803 
1804  pitscan = ksfse_scan_scanloop();
1805 
1806  return SUCCESS;
1807 
1808 } /* ksfse_eval_scantime() */
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int numlinestoacq
Definition: KSFoundation.h:1684
float ksfse_scan_scanloop()
Plays out all volumes and passes of a single or multi-pass scan
Definition: ksfse_implementation.e:2814
int ksfse_dda
Definition: ksfse_implementation.e:127

◆ ksfse_check()

STATUS ksfse_check ( )

Returns error of various parameter combinations that are not allowed for ksfse

Return values
STATUSSUCCESS or FAILURE
1827  {
1828 
1829  /* Show resolution, BW per pixel & echo spacing in the UI */
1830 #if EPIC_RELEASE >= 26
1831  piinplaneres = 1;
1832  pirbwperpix = 1;
1833  piesp = 1;
1834  ihinplanexres = ksfse.read.fov/ksfse.read.res;
1835  ihinplaneyres = ksfse.phaseenc.fov/ksfse.phaseenc.res;
1836  ihrbwperpix = (1000.0 * ksfse.read.acq.rbw * 2.0)/ksfse.read.res;
1837  ihesp = ksfse_esp/1000.0;
1838 #endif
1839 
1840  /* Force the user to select the Fast Spin echo button. This error needs to be in cvcheck(), not in
1841  cvinit()/cveval() to avoid it to trigger also when Fast Spin Echo has been selected */
1842  if (!((oppseq == PSD_SE || oppseq == PSD_IR) && opfast == PSD_ON && existcv(opfast))) {
1843  return ks_error("%s: Please first select the 'Fast Spin Echo' button", ks_psdname);
1844  }
1845 
1846  if (KS_3D_SELECTED && opcube) {
1847  return ks_error("%s: Please select either FRFSE-XL or FSE", __FUNCTION__);
1848  }
1849 
1850  if (oparc && KS_3D_SELECTED && (ksfse.zphaseenc.R > ksfse.phaseenc.R)) {
1851  /* Unclear why, but zR > R leads to corrupted images for ARC and 3D.
1852  Probably a bug that can be fixed later. Limited experience (July 2018) */
1853  return ks_error("%s: Need Slice acceleration <= Phase accleration", __FUNCTION__);
1854  }
1855 
1856  return SUCCESS;
1857 
1858 } /* ksfse_check() */
int R
Definition: KSFoundation.h:1680
int res
Definition: KSFoundation.h:1678
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
float fov
Definition: KSFoundation.h:1576
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
KS_READTRAP read
Definition: ksfse_implementation.e:51
float rbw
Definition: KSFoundation.h:734
char ks_psdname[256]
Definition: GERequired.e:221
int res
Definition: KSFoundation.h:1577
int ksfse_esp
Definition: ksfse_implementation.e:113
KS_READ acq
Definition: KSFoundation.h:1574
float fov
Definition: KSFoundation.h:1677

◆ ksfse_predownload_plot()

STATUS ksfse_predownload_plot ( KS_SEQ_COLLECTION seqcollection)

Plotting of sequence modules and slice timing to PNG/SVG/PDF files

The ks_plot_*** functions used in here will save plots to disk depending on the value of the CV ks_plot_filefmt (see KS_PLOT_FILEFORMATS). E.g. if ks_plot_filefmt = KS_PLOT_OFF, nothing will be written to disk. On the MR scanner, the output will be located in /usr/g/mrraw/plot/<ks_psdname>. In simulation, it will be placed in the current directory (./plot/).

Please see the documentation on how to install the required python version and links. Specifically, there must be a link /usr/local/bin/apython pointing to the Anaconda 2 python binary (v. 2.7).

In addition, the following text files are printed out

  • <ks_psdname>_objects.txt
  • <ks_psdname>_seqcollection.txt
Returns
STATUS SUCCESS or FAILURE
1890  {
1891  char tmpstr[1000];
1892 
1893  /* System wide (psd independent) option to disable plotting, to e.g. speed up UX on a slow MR show system */
1894  if (existfile("/usr/g/research/bin/ksdonotplot")) {
1895  return SUCCESS;
1896  }
1897 
1898 #ifdef PSD_HW
1899  sprintf(tmpstr, "/usr/g/mrraw/%s_objects.txt", ks_psdname);
1900 #else
1901  sprintf(tmpstr, "./%s_objects.txt", ks_psdname);
1902 #endif
1903  FILE *fp = fopen(tmpstr, "w");
1904 
1905  /* Note: 'fp' can be replaced with 'stdout' or 'stderr' to get these
1906  values printed out in the WTools window in simulation. However,
1907  heavy printing may result in that the WTools window closes,
1908  why we here write to a file ksfse_objects.txt instead */
1918  if (ksinv1.params.irmode != KSINV_OFF) {
1920  }
1921  fclose(fp);
1922 
1923 
1924  /* ks_plot_host():
1925  Plot each sequence module as a separate file (PNG/SVG/PDF depending on ks_plot_filefmt (GERequired.e))
1926  See KS_PLOT_FILEFORMATS in KSFoundation.h for options.
1927  Note that the phase encoding amplitudes corresponds to the first shot, as set by the call to ksfse_scan_seqstate below */
1930 
1931  /* Sequence timing plot: */
1935 
1936  /* ks_plot_tgt_reset():
1937  Creates sub directories and clear old files for later use of ksfse_scan_acqloop()->ks_plot_tgt_addframe().
1938  ks_plot_tgt_addframe() will only write in MgdSim (WTools) to avoid timing issues on the MR scanner. Hence,
1939  unlike ks_plot_host() and the sequence timing plot, one has to open MgdSim and press RunEntry (and also
1940  press PlotPulse several times after pressing RunEntry).
1941  ks_plot_tgt_reset() will create a 'makegif_***.sh' file that should be run in a terminal afterwards
1942  to create the animiated GIF from the dat files */
1944 
1945 
1946  return SUCCESS;
1947 
1948 } /* ksfse_predownload_plot() */
KS_TRAP grad
Definition: KSFoundation.h:1676
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KS_TRAP spoiler
Definition: ksfse_implementation.e:55
KS_SELRF selrfinv
Definition: KSInversion.e:102
KS_PHASER phaseenc
Definition: ksfse_implementation.e:53
STATUS ksfse_scan_seqstate(SCAN_INFO slice_info, int shot)
Sets the current state of all ksfse sequence objects being part of KSFSE_SEQUENCE
Definition: ksfse_implementation.e:2383
KS_PHASER zphaseenc
Definition: ksfse_implementation.e:54
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
void ks_plot_host(KS_SEQ_COLLECTION *seqcollection, KS_PHASEENCODING_PLAN *plan)
Definition: KSFoundation_host.c:5585
KS_READTRAP read
Definition: ksfse_implementation.e:51
int irmode
Definition: KSInversion.e:76
char ks_psdname[256]
Definition: GERequired.e:221
float ksfse_scan_scanloop()
Plays out all volumes and passes of a single or multi-pass scan
Definition: ksfse_implementation.e:2814
KS_TRAP readdephaser
Definition: ksfse_implementation.e:52
void ks_plot_slicetime_begin()
Definition: KSFoundation_common.c:3396
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
void ks_plot_slicetime_end()
Definition: KSFoundation_common.c:3437
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
void ks_print_phaser(KS_PHASER phaser, FILE *fp)
Writes out the contents of a KS_PHASER sequence object for debugging
Definition: KSFoundation_host.c:5198
void ks_print_trap(KS_TRAP trap, FILE *fp)
Writes out the contents of a KS_TRAP sequence object for debugging
Definition: KSFoundation_host.c:5168
STATUS STATUS STATUS existfile(const char *fname)
Definition: KSFoundation_common.c:175
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
void ks_plot_tgt_reset(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_common.c:3445
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksfse_implementation.e:62
void ks_print_selrf(KS_SELRF selrf, FILE *fp)
Writes out the contents of a KS_SELRF sequence object for debugging
Definition: KSFoundation_host.c:5316
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215
void ks_print_readtrap(KS_READTRAP readtrap, FILE *fp)
Writes out the contents of a KS_READTRAP sequence object for debugging
Definition: KSFoundation_host.c:5179

◆ ksfse_predownload_setrecon()

STATUS ksfse_predownload_setrecon ( )

Last-resort function to override certain recon variables not set up correctly already

For most cases, the GEReq_predownload_*** functions in predownload() in ksfse.e set up the necessary rh*** variables for the reconstruction to work properly. However, if this sequence is customized, certain rh*** variables may need to be changed. Doing this here instead of in predownload() directly separates these changes from the standard behavior.

Return values
STATUSSUCCESS or FAILURE
1964  {
1965 
1966  return SUCCESS;
1967 
1968 } /* ksfse_predownload_setrecon() */

◆ ksfse_etlphaseamps()

STATUS ksfse_etlphaseamps ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
KS_PHASER phaser,
KS_PHASER zphaser,
int  shot 
)

Sets the phase encoding amplitudes in the FSE train on hardware using the phase enc. table and shot index

This function will quietly return early when called on HOST. On IPG, it will set the instruction amplitudes of the phase encoding gradients in the FSE train given the phase encoding table, the pointer to the single phase encoding object for all phase encodes in the echo train, and the shot index.

The shot index must be in range [0, ceil(pe.numlinestoacq/etl)] and is used to select the current row of etl different amplitudes in phaseenc_plan[][shot].

The KS_PHASER object must have been placed out 2*etl times in ksfse_pg() before calling this function. The etl dephasing gradients before each readout in the echo train correspond to even indices, i.e. 0,2,4,...,(2*etl-1), whereas the rephasing gradients after each readout correspond to odd indices. This is an effect of that all ks_pg_***() functions sort the instances of an object in time.

If shot < 0 (e.g. shot = KS_NOTSET = -1), all phase encoding amplitudes will be set to zero.

Parameters
[in]phaseenc_plan_ptrPointer to the phase encoding table (KS_PHASEENCODING_PLAN) (2D & 3D)
[in]phaserPointer to a KS_PHASER ("ky")
[in]zphaserPointer to a KS_PHASER ("kz"). Pass in NULL for 2D
[in]shotWhich shot index to play out for this echo train. shot = KS_NOTSET will set all phase encoding gradients to zero.
Return values
STATUSSUCCESS or FAILURE
2015  {
2016  int echo;
2018 
2019  if (phaseenc_plan_ptr->etl == KS_NOTSET) {
2020  return SUCCESS; /* we haven't set it up yet */
2021  }
2022 
2023  /* TODO: Check that #instance for phaser and zphaser is equal to phaseenc_plan_ptr->etl * 2 - 1.
2024  If 1 less that 2*etl, this indicates no fastrecovery. Don't need the last arg then */
2025 
2026  for (echo = 0; echo < phaseenc_plan_ptr->etl; echo++) {
2027 
2028  coord = ks_phaseencoding_get(phaseenc_plan_ptr, echo, shot);
2029 
2030  ks_scan_phaser_toline(phaser, 0 + 2 * echo, coord.ky); /* dephaser */
2031  ks_scan_phaser_fromline(phaser, 1 + 2 * echo, coord.ky); /* rephaser */
2032 
2033  if (zphaser != NULL) {
2034  ks_scan_phaser_toline(zphaser, 0 + 2 * echo, coord.kz); /* dephaser */
2035  ks_scan_phaser_fromline(zphaser, 1 + 2 * echo, coord.kz); /* rephaser */
2036  }
2037 
2038  } /* for echo in etl */
2039 
2040  return SUCCESS;
2041 
2042 } /* ksfse_etlphaseamps() */
#define KS_INIT_PHASEENCODING_COORD
Definition: KSFoundation.h:219
#define KS_NOTSET
Definition: KSFoundation.h:103
int ky
Definition: KSFoundation.h:1705
int kz
Definition: KSFoundation.h:1706
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1704
KS_PHASEENCODING_COORD ks_phaseencoding_get(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int echo, int shot)
Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given echo and shot
Definition: KSFoundation_common.c:375
int etl
Definition: KSFoundation.h:1740
void ks_scan_phaser_toline(KS_PHASER *phaser, int instanceno, int view)
Updates the amplitude of a KS_PHASER sequence object to move from the k-space center to a desired k-s...
Definition: KSFoundation_tgt.c:340
void ks_scan_phaser_fromline(KS_PHASER *phaser, int instanceno, int view)
Updates the amplitude of a KS_PHASER sequence object to move from a k-space line to the k-space cente...
Definition: KSFoundation_tgt.c:359

◆ ksfse_spoilamp()

void ksfse_spoilamp ( KS_PHASEENCODING_PLAN phaseenc_plan_ptr,
KS_TRAP spoiler,
int  res,
int  shot 
)

2DFSE: Updates the spoiler amplitude on hardware during scanning depending on current etl and shot

This function updates the spoiler amplitude during scanning, and will return quietly if called on HOST.

Parameters
[in]phaseenc_plan_ptrPointer to the phase encoding table (KS_PHASEENCODING_PLAN) (2D & 3D)
[in]spoilerPointer to the KS_TRAP spoiler object
[in]resPhase encoding resolution
[in]shotshot index in range [0, ceil(pe.numlinestoacq/etl)].
Returns
void
2059  {
2061 
2062  /* change spoil direction with respect to last phase encoding blip */
2063  if (shot >= 0) {
2064  int i = 1;
2065  double kspace_dist = 0.0;
2066  for (i = 0; i < phaseenc_plan_ptr->etl; i++) {
2067  coord = ks_phaseencoding_get(phaseenc_plan_ptr, i, shot);
2068  if (coord.ky != KS_NOTSET) {
2069  kspace_dist = ((res - 1.0) / 2.0) - coord.ky;
2070  }
2071  }
2072  if (kspace_dist >= 0.0) {
2073  coord = ks_phaseencoding_get(phaseenc_plan_ptr, phaseenc_plan_ptr->etl - 1, shot);
2074  if (coord.ky == KS_NOTSET) {
2075  ks_scan_trap_ampscale(spoiler, 0, -1.0);
2076  } else {
2077  ks_scan_trap_ampscale(spoiler, 0, 1.0);
2078  }
2079  } else {
2080  coord = ks_phaseencoding_get(phaseenc_plan_ptr, phaseenc_plan_ptr->etl - 1, shot);
2081  if (coord.ky == KS_NOTSET) {
2082  ks_scan_trap_ampscale(spoiler, 0, 1.0);
2083  } else {
2084  ks_scan_trap_ampscale(spoiler, 0, -1.0);
2085  }
2086  }
2087  }
2088 
2089 } /* ksfse_spoilamp() */
#define KS_INIT_PHASEENCODING_COORD
Definition: KSFoundation.h:219
void ks_scan_trap_ampscale(KS_TRAP *trap, int instanceno, float ampscale)
Updates the amplitude of one or all instances of a KS_TRAP sequence object
Definition: KSFoundation_tgt.c:199
#define KS_NOTSET
Definition: KSFoundation.h:103
int32_t i
Definition: KSFoundation_tgt.c:1389
int ky
Definition: KSFoundation.h:1705
Struct holding a 3D k-space phase encoding location (ky,kz)
Definition: KSFoundation.h:1704
KS_PHASEENCODING_COORD ks_phaseencoding_get(const KS_PHASEENCODING_PLAN *phaseenc_plan_ptr, int echo, int shot)
Get [ky,kz] coordinate from KS_PHASEENCODING_PLAN for given echo and shot
Definition: KSFoundation_common.c:375
int etl
Definition: KSFoundation.h:1740

◆ ksfse_scan_rf_off()

void ksfse_scan_rf_off ( )

Sets all RF pulse amplitudes to zero

Returns
void
2460  {
2461  ks_scan_rf_off(&ksfse.selrfexc.rf, INSTRALL);
2462  ks_scan_rf_off(&ksfse.selrfref1st.rf, INSTRALL);
2463  ks_scan_rf_off(&ksfse.selrfref2nd.rf, INSTRALL);
2464  ks_scan_rf_off(&ksfse.selrfref.rf, INSTRALL);
2465  ks_scan_rf_off(&ksfse.selrfrecover.rf, INSTRALL);
2466  ks_scan_rf_off(&ksfse.selrfrecoverref.rf, INSTRALL);
2467 } /* ksfse_scan_rf_off() */
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
void ks_scan_rf_off(KS_RF *rf, int instanceno)
Sets the amplitude of one or all instances of an RF pulse (KS_RF) to zero
Definition: KSFoundation_tgt.c:469
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60

◆ ksfse_scan_rf_on()

void ksfse_scan_rf_on ( )

Sets all RF pulse amplitudes on

Returns
void
2477  {
2478  ks_scan_rf_on(&ksfse.selrfexc.rf, INSTRALL);
2479  ks_scan_rf_on(&ksfse.selrfref1st.rf, INSTRALL);
2480  ks_scan_rf_on(&ksfse.selrfref2nd.rf, INSTRALL);
2481  ks_scan_rf_on(&ksfse.selrfref.rf, INSTRALL);
2482  ks_scan_rf_on(&ksfse.selrfrecover.rf, INSTRALL);
2483  ks_scan_rf_on(&ksfse.selrfrecoverref.rf, INSTRALL);
2484 }
void ks_scan_rf_on(KS_RF *rf, int instanceno)
Resets the amplitude of one or all instances of an RF pulse (KS_RF)
Definition: KSFoundation_tgt.c:442
KS_SELRF selrfrecoverref
Definition: ksfse_implementation.e:61
KS_SELRF selrfexc
Definition: ksfse_implementation.e:56
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
KS_SELRF selrfref2nd
Definition: ksfse_implementation.e:58
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfref
Definition: ksfse_implementation.e:59
KS_SELRF selrfref1st
Definition: ksfse_implementation.e:57
KS_SELRF selrfrecover
Definition: ksfse_implementation.e:60

◆ ksfse_scan_init()

STATUS ksfse_scan_init ( void  )

Common initialization for prescan entry points MPS2 and APS2 as well as the SCAN entry point

Return values
STATUSSUCCESS or FAILURE
2866  {
2867 
2868  GEReq_initRSP();
2869 
2870  /* Here goes code common for APS2, MPS2 and SCAN */
2871 
2872  ks_scan_switch_to_sequence(&ksfse.seqctrl); /* switch to main sequence */
2873  scopeon(&seqcore); /* Activate scope for core */
2874  syncon(&seqcore); /* Activate sync for core */
2875  setssitime(ksfse.seqctrl.ssi_time / HW_GRAD_UPDATE_TIME);
2876 
2877  /* can we make these independent on global rsptrigger and rsprot in orderslice? */
2878  settriggerarray( (short) ks_slice_plan.nslices_per_pass, rsptrigger);
2879 
2880  return SUCCESS;
2881 
2882 } /* ksfse_scan_init() */
void ks_scan_switch_to_sequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1356
STATUS setssitime(long)
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int nslices_per_pass
Definition: KSFoundation.h:1353
void GEReq_initRSP(void)
RSP Init. To be inserted in the psdinit() function (or scan()) in the main sequence
Definition: GERequired.e:2683
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
int ssi_time
Definition: KSFoundation.h:1134
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217

◆ ksfse_scan_prescanloop()

STATUS ksfse_scan_prescanloop ( int  nloops,
int  dda 
)

Prescan loop called from both APS2 and MPS2 entry points

Return values
STATUSSUCCESS or FAILURE
2892  {
2893  int i, echoindx, sltimeinpass, slloc;
2894  int centerecho = IMin(2, opetl-1, opte / ksfse_esp);
2895 
2896  /* turn off receivers for all echoes */
2897  for (echoindx = 0; echoindx < ksfse.read.acq.base.ngenerated; echoindx++) {
2898  loaddab(&ksfse.read.acq.echo[echoindx], 0, 0, DABSTORE, 0, DABOFF, PSD_LOAD_DAB_ALL);
2899  }
2900 
2901  /* play dummy scans to get into steady state */
2902  for (i = -dda; i < nloops; i++) {
2903 
2904  /* loop over slices */
2905  for (sltimeinpass = 0; sltimeinpass < ks_slice_plan.nslices_per_pass; sltimeinpass++) {
2906 
2907  /* slice location from slice plan */
2908  slloc = ks_scan_getsliceloc(&ks_slice_plan, 0, sltimeinpass);
2909 
2910  if (slloc != KS_NOTSET) {
2911  /* modify sequence for next playout */
2912  ksfse_scan_rf_on();
2913  ksfse_scan_seqstate(ks_scan_info[slloc], KS_NOTSET); /* KS_NOTSET => no phase encodes */
2914 
2915  } else {
2917  }
2918 
2919  /* data routing control */
2920  if (i >= 0) {
2921  /* turn on receiver for center echo */
2922  loaddab(&ksfse.read.acq.echo[centerecho], 0, 0, DABSTORE, 0, DABON, PSD_LOAD_DAB_ALL);
2923  }
2924 
2926 
2927  } /* for slices */
2928 
2929  } /* for nloops */
2930 
2931 
2932  return SUCCESS;
2933 
2934 } /* ksfse_scan_prescanloop() */
WF_PULSE * echo
Definition: KSFoundation.h:738
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ksfse_scan_seqstate(SCAN_INFO slice_info, int shot)
Sets the current state of all ksfse sequence objects being part of KSFSE_SEQUENCE
Definition: ksfse_implementation.e:2383
KSFSE_SEQUENCE ksfse
Definition: ksfse_implementation.e:148
int32_t i
Definition: KSFoundation_tgt.c:1389
KS_READTRAP read
Definition: ksfse_implementation.e:51
KS_BASE base
Definition: KSFoundation.h:731
int nslices_per_pass
Definition: KSFoundation.h:1353
void ksfse_scan_rf_on()
Sets all RF pulse amplitudes on
Definition: ksfse_implementation.e:2477
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1368
KS_SEQ_CONTROL seqctrl
Definition: ksfse_implementation.e:50
int ksfse_esp
Definition: ksfse_implementation.e:113
KS_SLICE_PLAN ks_slice_plan
Definition: GERequired.e:217
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
void ksfse_scan_rf_off()
Sets all RF pulse amplitudes to zero
Definition: ksfse_implementation.e:2460
int ngenerated
Definition: KSFoundation.h:410
KS_READ acq
Definition: KSFoundation.h:1574
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

Variable Documentation

◆ seqcollection

KS_SEQ_COLLECTION seqcollection

◆ ksfse_excthickness

float ksfse_excthickness = 0

◆ ksfse_gscalerfexc

float ksfse_gscalerfexc = 0.9

◆ ksfse_flipexc

float ksfse_flipexc = 90.0 with {0.0, 180.0, 90.0, VIS, "Excitation flip angle [deg]",}

◆ ksfse_spoilerarea

float ksfse_spoilerarea = 2000.0 with {0.0, 20000.0, 5000.0, VIS, "ksfse spoiler gradient area",}

◆ rf_stretch_rfexc

float rf_stretch_rfexc = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF excitation pulse if > 1.0",}

◆ ksfse_inflowsuppression

int ksfse_inflowsuppression = 0 with {0, 1, 0, VIS, "In-flow Suppression [0:OFF, 1:ON]",}

◆ ksfse_inflowsuppression_mm

float ksfse_inflowsuppression_mm = 0.0 with {0.0, 100.0, 0.0, VIS, "In-flow suppression [mm]",}

◆ ksfse_vfa

int ksfse_vfa = 1 with {0, 1, 1, VIS, "Variable flip angles [0:OFF, 1:ON]",}

◆ ksfse_crusherscale

float ksfse_crusherscale = 0.5 with {0.0, 20.0, 0.5, VIS, "scaling of crusher gradient area",}

◆ ksfse_gscalerfref

float ksfse_gscalerfref = 0.9

◆ ksfse_slicecheck

int ksfse_slicecheck = 0 with {0, 1, 0, VIS, "move readout to z axis for slice thickness test",}

◆ rf_stretch_rfref

float rf_stretch_rfref = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF refocusing pulses if > 1.0",}

◆ rf_stretch_all

float rf_stretch_all = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch all RF pulses if > 1.0",}

◆ ksfse_recovery

int ksfse_recovery = KSFSE_RECOVERY_OFF with {KSFSE_RECOVERY_OFF, KSFSE_RECOVERY_FAST, KSFSE_RECOVERY_OFF, VIS, "Recovery. 0:off 1:T1wopt 2:T2fast", }

◆ rf_stretch_rfrecovery

float rf_stretch_rfrecovery = 1.0 with {0.01, 100.0, 1.0, VIS, "Stretch RF recovery pulses if > 1.0",}

◆ ksfse_kxnover_min

int ksfse_kxnover_min = KSFSE_MINHNOVER with {KSFSE_MINHNOVER, 512, KSFSE_MINHNOVER, VIS, "Min mum kx overscans for minTE",}

◆ ksfse_kxnover

int ksfse_kxnover = 32 with {KSFSE_MINHNOVER, 512, 32, VIS, "Num kx overscans for minTE",}

◆ ksfse_rampsampling

int ksfse_rampsampling = 0 with {0, 1, 0, VIS, "Rampsampling [0:OFF 1:ON]",}

◆ ksfse_extragap

int ksfse_extragap = 0 with {0, 100ms, 0, VIS, "extra gap between readout [us]",}

◆ ksfse_etlte

int ksfse_etlte = 1 with {0, 1, 1, VIS, "ETL controls TE",}

◆ ksfse_xcrusherarea

float ksfse_xcrusherarea = 100.0 with {0.0, 1000.0, 100.0, VIS, "x crusher area for readout",}

◆ ksfse_esp

int ksfse_esp = 0 with {0, 1000000, 0, VIS, "View-only: Echo spacing in [us]",}

◆ ksfse_noph

int ksfse_noph = 0 with {0, 1, 0, VIS, "Turn OFF phase encoding [0:Disabled 1:Enabled]",}

◆ ksfse_minacslines

int ksfse_minacslines = 12 with {0, 512, 12, VIS, "Minimum ACS lines for ARC",}

◆ ksfse_minzacslines

int ksfse_minzacslines = 12 with {0, 512, 12, VIS, "Minimum z ACS lines for ARC",}

◆ ksfse_pos_start

int ksfse_pos_start = KS_RFSSP_PRETIME with {0, , KS_RFSSP_PRETIME, VIS, "us from start until the first waveform begins",}

◆ ksfse_ssi_time

int ksfse_ssi_time = KSFSE_MIN_SSI_TIME with {50, , KSFSE_MIN_SSI_TIME, VIS, "time from eos to ssi in intern trig",}

◆ ksfse_dda

int ksfse_dda = 2 with {0, 200, 2, VIS, "Number of dummy scans for steady state",}

◆ ksfse_debug

int ksfse_debug = 1 with {0, 100, 1, VIS, "Write out e.g. plot files (unless scan on HW)",}

◆ ksfse_imsize

int ksfse_imsize = KS_IMSIZE_NATIVE with {KS_IMSIZE_NATIVE, KS_IMSIZE_MIN256, KS_IMSIZE_MIN256, VIS, "img. upsamp. [0:native 1:pow2 2:min256]"}

◆ ksfse_abort_on_kserror

int ksfse_abort_on_kserror = FALSE with {0, 1, 0, VIS, "Hard program abort on ks_error [0:OFF 1:ON]",}

◆ ksfse_mintr

int ksfse_mintr = 0 with {0, 20s, 0, VIS, "Min TR (ms) [0: Disabled]",}

◆ ksfse_maxtr

int ksfse_maxtr = 0 with {0, 40s, 0, VIS, "Max TR (ms) [0: Disabled]",}

◆ ksfse

◆ sequence_iopts

int sequence_iopts[]
Initial value:
= {
PSD_IOPT_ARC,
PSD_IOPT_ASSET,
PSD_IOPT_EDR,
PSD_IOPT_DYNPL,
PSD_IOPT_TLRD_RF,
PSD_IOPT_MILDNOTE,
PSD_IOPT_ZIP_512,
PSD_IOPT_FR,
PSD_IOPT_T1FLAIR,
PSD_IOPT_T2FLAIR,
PSD_IOPT_IR_PREP,
}

◆ volindx

int volindx

◆ passindx

int passindx