KSFoundation  [April-2021]
A platform for simpler EPIC programming on GE MR systems
Classic sequence modules

Data Structures

struct  KSCHEMSAT_PARAMS
 
struct  KSCHEMSAT_SEQUENCE
 
struct  KSINV_PARAMS
 
struct  KSINV_SEQUENCE
 
struct  KSSPSAT_VOLBORDER
 
struct  KSSPSAT_LOC
 
struct  KSSPSAT_PARAMS
 
struct  KSSPSAT_SEQUENCE
 

Macros

#define KSCHEMSAT_MODULE_LOADED   /* can be used to check whether the KSChemsat module has been included in a main psd */
 
#define KSCHEMSAT_DEFAULT_FLIP   95
 
#define KSCHEMSAT_DEFAULT_SINCRF_BW_15T   150 /* for 1.5T */
 
#define KSCHEMSAT_DEFAULT_SINCRF_BW_3T   300 /* for 3T */
 
#define KSCHEMSAT_DEFAULT_SINCRF_TBP   4
 
#define KSCHEMSAT_DEFAULT_SPOILERAREA   5000
 
#define KSCHEMSAT_DEFAULT_SSITIME   1000 /* try to reduce this value */
 
#define KSCHEMSAT_INIT_PARAMS   {KSCHEMSAT_OFF, KSCHEMSAT_DEFAULT_FLIP, 0, KSCHEMSAT_RF_STD, KSCHEMSAT_DEFAULT_SINCRF_BW_3T, KSCHEMSAT_DEFAULT_SINCRF_TBP, KSCHEMSAT_DEFAULT_SPOILERAREA, KSCHEMSAT_DEFAULT_SSITIME}
 
#define KSCHEMSAT_INIT_SEQUENCE   {{0,0,NULL,sizeof(KSCHEMSAT_SEQUENCE)}, KS_INIT_SEQ_CONTROL, KSCHEMSAT_INIT_PARAMS, KS_INIT_RF, KS_INIT_TRAP}
 
#define KSINV_MODULE_LOADED   /* can be used to check whether the KSInversion module has been included in a main psd */
 
#define KSINV_DEFAULT_FLIP   180
 
#define KSINV_DEFAULT_SPOILERAREA   5000
 
#define KSINV_DEFAULT_SSITIME   1000 /* try to reduce this value */
 
#define KSINV_DEFAULT_STARTPOS   100
 
#define KSINV_FILLTR_SSITIME   1000 /* try to reduce this value */
 
#define KSINV_MINTR_T2FLAIR   8000000 /* default minTR [us] for T2FLAIR, 8 [s] */
 
#define KSINV_MINTR_T1FLAIR   1300000 /* default minTR [us] for T1FLAIR, 1.3 [s] */
 
#define KSINV_MAXTR_T1FLAIR   2500000 /* default maxTR [us] for T1FLAIR, 2.5 [s] */
 
#define KSINV_MAXTHICKFACT   3.0 /* how much the inversion slice thickness may increase over opslthick */
 
#define KSINV_MAXTHICKFACT_T1FLAIR   1.5
 
#define T1_CSF_3T   4500
 
#define T1_CSF_1_5T   3600
 
#define T1_GM_3T   1400
 
#define T1_GM_1_5T   1100
 
#define T1_WM_3T   750
 
#define T1_WM_1_5T   600
 
#define T1_FAT_3T   340
 
#define T1_FAT_1_5T   260
 
#define KSINV_INIT_PARAMS   {KSINV_OFF, KSINV_DEFAULT_FLIP, KS_NOTSET, 0, KSINV_RF_STD, KSINV_DEFAULT_SPOILERAREA, FALSE, KSINV_DEFAULT_STARTPOS, 0, 0, KSINV_DEFAULT_SSITIME, 90, KS_NOTSET, 1, KS_NOTSET, KSINV_RF_STD}
 
#define KSINV_INIT_SEQUENCE   {{0,0,NULL,sizeof(KSINV_SEQUENCE)}, KS_INIT_SEQ_CONTROL, KSINV_INIT_PARAMS, KS_INIT_SELRF, KS_INIT_TRAP, KS_INIT_SELRF, KS_INIT_SELRF, KS_INIT_SELRF}
 
#define KSINV_PIUSE(o1, o2, o3, o4)
 
#define KSINV_OPUSER_VALS(o1, o2, o3, o4)
 
#define KSINV_OPUSER_STRUCTS(o1, o2, o3, o4)
 
#define KSINV_EVAL(sptr, o1, o2, o3, o4)
 
#define KSINV_EVAL_CUSTOMRF(sptr, rfptr, o1, o2, o3, o4)
 
#define KSSPSAT_MODULE_LOADED   /* can be used to check whether the KSSpsat module has been included in a main psd */
 
#define KSSPSAT_DEFAULT_FLIP   95
 
#define KSSPSAT_DEFAULT_SPOILERSCALE   5.0
 
#define KSSPSAT_DEFAULT_SPOILALLAXES   1
 
#define KSSPSAT_DEFAULT_SSITIME   1000 /* try to reduce this value */
 
#define KSSPSAT_EXPLICITSAT_DISABLED   9990.0 /* Set by UI on MR-scanner */
 
#define KSSPSAT_IMPLICITSAT_DISABLED   9999.0 /* Set by UI on MR-scanner */
 
#define KSSPSAT_INIT_VOLBORDER   {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
 
#define KSSPSAT_INIT_LOC   {DEFAULT_AXIAL_SCAN_INFO, 0, KS_NOTSET, KSSPSAT_OFF}
 
#define KSSPSAT_INIT_PARAMS   {KSSPSAT_INIT_VOLBORDER, KSSPSAT_DEFAULT_FLIP, KSSPSAT_RF_COMPLEX, KSSPSAT_DEFAULT_SPOILERSCALE, KSSPSAT_DEFAULT_SPOILALLAXES, PSD_OBL_RESTRICT, KSSPSAT_DEFAULT_SSITIME}
 
#define KSSPSAT_INIT_SEQUENCE   {{0,0,NULL,sizeof(KSSPSAT_SEQUENCE)}, KS_INIT_SEQ_CONTROL, KSSPSAT_INIT_LOC, KS_INIT_SELRF}
 

Enumerations

enum  { KSCHEMSAT_OFF, KSCHEMSAT_FAT, KSCHEMSAT_WATER }
 
enum  { KSCHEMSAT_RF_STD, KSCHEMSAT_RF_SINC }
 
enum  {
  KSINV_OFF, KSINV_IR_SIMPLE, KSINV_IR_SLICEAHEAD, KSINV_FLAIR_BLOCK,
  KSINV_FLAIR_T2PREP_BLOCK
}
 
enum  { KSINV_RF_STD, KSINV_RF_ADIABATIC, KSINV_RF_CUSTOM }
 
enum  KSINV_LOOP_MODE { KSINV_LOOP_NORMAL, KSINV_LOOP_DUMMY, KSINV_LOOP_SLICEAHEAD_FIRST, KSINV_LOOP_SLICEAHEAD_LAST }
 
enum  { KSSPSAT_OFF, KSSPSAT_IMPLICIT, KSSPSAT_EXPLICIT }
 
enum  {
  KSSPSAT_1, KSSPSAT_2, KSSPSAT_3, KSSPSAT_4,
  KSSPSAT_5, KSSPSAT_6, KSSPSAT_MAXNUMSAT
}
 
enum  { KSSPSAT_NEG =1, KSSPSAT_POS, KSSPSAT_HAD, KSSPSAT_PARA }
 
enum  { KSSPSAT_RF_STD, KSSPSAT_RF_COMPLEX, KSSPSAT_RF_MAXRFTYPES }
 

Functions

int kschemsat_pg (KSCHEMSAT_SEQUENCE *kschemsat)
 
void kschemsat_init_params (KSCHEMSAT_PARAMS *params)
 
void kschemsat_init_sequence (KSCHEMSAT_SEQUENCE *kschemsat)
 
void kschemsat_eval_copycvs (KSCHEMSAT_PARAMS *params)
 
STATUS kschemsat_eval_setupobjects (KSCHEMSAT_SEQUENCE *kschemsat)
 
STATUS kschemsat_eval (KS_SEQ_COLLECTION *seqcollection)
 
void kschemsat_scan_seqstate (KSCHEMSAT_SEQUENCE *kschemsat)
 
STATUS ksinv_eval_checkTR_SAR (KS_SEQ_COLLECTION *seqcollection, KS_SLICE_PLAN *slice_plan, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
 
int ksinv_pg (KSINV_SEQUENCE *ksinv)
 
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)
 
void ksinv_init_params (KSINV_PARAMS *params)
 
void ksinv_init_sequence (KSINV_SEQUENCE *ksinv)
 
void ksinv_eval_copycvs (KSINV_PARAMS *params, int mode)
 
STATUS ksinv_eval_setuprf (KSINV_SEQUENCE *ksinv, const char *suffix, KS_SELRF *custom_selrf)
 
STATUS ksinv_eval_setupt2prep (KSINV_SEQUENCE *ksinv)
 
STATUS ksinv_eval_setupobjects (KSINV_SEQUENCE *ksinv, const char *suffix, KS_SELRF *custom_selrf)
 
int ksinv_eval_nullti (int TR, int T1value, int seqdur)
 
STATUS ksinv_eval_duration (KSINV_SEQUENCE *ksinv, int TI, int coreslice_momentstart)
 
STATUS ksinv_eval_duration_t1value (KSINV_SEQUENCE *ksinv, int *TR, int *TI, int approxti_flag, int coreslice_momentstart, int coreslice_duration, int mainseq_mindur, int T1value_toNull, int slperpass)
 
STATUS ksinv_eval_duration_flairblock (KSINV_SEQUENCE *ksinv, int TI, int coreslice_momentstart, int coreslice_duration, int slperpass)
 
STATUS ksinv_eval_setfilltr (KS_SEQ_CONTROL *filltr, const char *const desc, int duration)
 
STATUS ksinv_init_UI ()
 
STATUS ksinv_eval_UI ()
 
STATUS ksinv_eval (KS_SEQ_COLLECTION *seqcollection, KS_SELRF *custom_selrf)
 
int ksinv_eval_mintr (const KS_SLICE_PLAN *slice_plan, KS_SEQ_COLLECTION *seqcollection, float gheatfact, KSINV_SEQUENCE *ksinv1, KSINV_SEQUENCE *ksinv2, KS_SEQ_CONTROL *ksinv_filltr, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
 
int ksinv_eval_maxslicespertr (int TR, KS_SLICE_PLAN temp_slice_plan, KS_SEQ_COLLECTION *seqcollection, float gheatfact, KSINV_SEQUENCE *ksinv1, KSINV_SEQUENCE *ksinv2, KS_SEQ_CONTROL *ksinv_filltr, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
 
STATUS ksinv_eval_flairblock (KSINV_SEQUENCE *ksinv, int *filltr_time, int *repetition_time, int *inversion_time, int autotr_flag, int T1tonull, int coreslice_momentstart, int coreslice_duration, int slperpass)
 
STATUS ksinv_eval_flairblock_withmainupdate (KSINV_SEQUENCE *ksinv, KS_SEQ_CONTROL *ksinv_filltr, KS_SEQ_CONTROL *mainseqctrl, int *repetition_time, int *inversion_time, int autotr_flag, int T1tonull, int coreslice_momentstart, int coreslice_duration, int slperpass)
 
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)
 
STATUS ksinv_check ()
 
STATUS ksinv_predownload_setrecon ()
 
void ksinv_pulsegen ()
 
STATUS ksinv_scan_seqstate (KSINV_SEQUENCE *ksinv, const SCAN_INFO *slice_info)
 
int ksinv_scan_irslice (KSINV_SEQUENCE *ksinv, const SCAN_INFO *slice_pos)
 
int ksinv_scan_sliceloop_nargs (int slperpass, int nargs, void **args)
 
int ksspsat_pg (KSSPSAT_SEQUENCE *ksspsat)
 
void ksspsat_scan_seqstate (KSSPSAT_SEQUENCE *ksspsat, float rfphase)
 
void ksspsat_init_params (KSSPSAT_PARAMS *params)
 
void ksspsat_init_sequence (KSSPSAT_SEQUENCE *ksspsat)
 
void ksspsat_eval_copycvs (KSSPSAT_PARAMS *params)
 
int ksspsat_eval_numsats (KSSPSAT_SEQUENCE *ksspsat)
 
STATUS ksspsat_eval_volborder (KSSPSAT_VOLBORDER *v)
 
STATUS ksspsat_eval_satplacements_from_UI (KSSPSAT_SEQUENCE *ksspsat, KSSPSAT_PARAMS *params)
 
STATUS ksspsat_eval_satplacements_dump (KSSPSAT_SEQUENCE *ksspsat, KSSPSAT_PARAMS *params)
 
STATUS ksspsat_eval_loggrd (LOG_GRAD *satloggrd, SCAN_INFO *slice_info, int satoblmethod)
 
STATUS ksspsat_eval_setupobjects ()
 
STATUS ksspsat_eval (KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksspsat_pulsegen ()
 
int ksspsat_scan_playsequences (int perform_slicetimeplot)
 

Variables

KSCHEMSAT_SEQUENCE kschemsat = KSCHEMSAT_INIT_SEQUENCE
 
int kschemsat_flag = KSCHEMSAT_OFF with {KSCHEMSAT_OFF, KSCHEMSAT_WATER, KSCHEMSAT_OFF, VIS, "flag for kschemsat (0:Off 1:FatSat 2:WaterSat)",}
 
float kschemsat_flip = KSCHEMSAT_DEFAULT_FLIP with {0, 360, KSCHEMSAT_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}
 
int kschemsat_rftype = KSCHEMSAT_RF_STD with {KSCHEMSAT_RF_STD, KSCHEMSAT_RF_SINC, KSCHEMSAT_RF_STD, VIS, "RF type (0:Std 1:Sinc)",}
 
int kschemsat_sinc_bw = KSCHEMSAT_DEFAULT_SINCRF_BW_3T with {2, 100000, 300, VIS, "Sinc RF BW",}
 
int kschemsat_sinc_tbp = KSCHEMSAT_DEFAULT_SINCRF_TBP with {2, 20, 2, VIS, "Sinc RF Time-Bandwidth-Product",}
 
int kschemsat_rfoffset = 0 with {-1000, 1000, 0, VIS, "RF excitation freq offset [Hz]",}
 
float kschemsat_spoilerarea = KSCHEMSAT_DEFAULT_SPOILERAREA with {0, 10000, KSCHEMSAT_DEFAULT_SPOILERAREA, VIS, "Spoiler area",}
 
int kschemsat_ssi_time = KSCHEMSAT_DEFAULT_SSITIME with {10, 20000, KSCHEMSAT_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}
 
KSINV_SEQUENCE ksinv1 = KSINV_INIT_SEQUENCE
 
KSINV_SEQUENCE ksinv2 = KSINV_INIT_SEQUENCE
 
KS_SEQ_CONTROL ksinv_filltr = KS_INIT_SEQ_CONTROL
 
int ksinv1_ti = 0
 
int ksinv2_ti = 0
 
int use_ir1_mode = 0
 
int use_ir1_t1 = 0
 
int use_ir2_mode = 0
 
int use_ir2_t1 = 0
 
float * ksinv1_mode = NULL
 
float * ksinv2_mode = NULL
 
float * ksinv1_t1value = NULL
 
float * ksinv2_t1value = NULL
 
_cvfloat * _ksinv1_mode = NULL
 
_cvfloat * _ksinv2_mode = NULL
 
_cvfloat * _ksinv1_t1value = NULL
 
_cvfloat * _ksinv2_t1value = NULL
 
int ksinv_ssi_time = KSINV_DEFAULT_SSITIME with {10, 20000, KSINV_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}
 
int ksinv_filltr_ssi_time = KSINV_FILLTR_SSITIME with {10, 20000, KSINV_FILLTR_SSITIME, VIS, "Time from eos to ssi in intern trig",}
 
int ksinv_mintr_t2flair = KSINV_MINTR_T2FLAIR with {0, 30s, KSINV_MINTR_T2FLAIR, VIS, "Min TR for T2-FLAIR",}
 
int ksinv_mintr_t1flair = KSINV_MINTR_T1FLAIR with {0, 30s, KSINV_MINTR_T1FLAIR, VIS, "Min TR for T1-FLAIR",}
 
int ksinv_maxtr_t1flair = KSINV_MAXTR_T1FLAIR with {0, 30s, KSINV_MAXTR_T1FLAIR, VIS, "Max TR for T1-FLAIR",}
 
int ksinv_slicecheck = 0 with {0, 1, 0, VIS, "move slice sel to x axis for slice thickness test",}
 
int ksinv_approxti = 1 with {0, 1, 1, VIS, "allow approx. TI for sliceahead IR mode",}
 
float ksinv_flip = KSINV_DEFAULT_FLIP with {0, 360, KSINV_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}
 
float ksinv_slthickfact = 1.0 with {0, KSINV_MAXTHICKFACT, 1.0, VIS, "Inversion sl.thick / opslthick factor",}
 
int ksinv_rfoffset = 0 with { -10000, 10000, 0, VIS, "RF excitation freq offset [Hz]",}
 
int ksinv_rftype = KSINV_RF_ADIABATIC with {KSINV_RF_STD, KSINV_RF_ADIABATIC, KSINV_RF_ADIABATIC, VIS, "RF type (0:Std 1:Adiabatic)",}
 
float ksinv_spoilerarea = KSINV_DEFAULT_SPOILERAREA with {0, 100000, KSINV_DEFAULT_SPOILERAREA, VIS, "Spoiler area",}
 
int ksinv_startpos = KSINV_DEFAULT_STARTPOS with {16, 10000, KSINV_DEFAULT_STARTPOS, VIS, "Start time of the first grad/RF inversion pulse in sequence module",}
 
int ksinv_t2prep = 0 with {0, 1, 0, VIS, "Use T2 preperation instead of conventional Inversion",}
 
int ksinv_t2prep_exc_flip = 90 with {0, 180, 90, VIS, "Flip angle of the excitation pulse and the flip down/up pulse for T2 prep",}
 
int ksinv_t2prep_N_Refoc = 1 with {1, 16, 1, VIS, "Number of refocusing pulses in the T2 inversion preperation",}
 
int ksinv_t2prep_TE = 100ms with {30ms, 300ms, 100ms, VIS, "TE for T2 inv preperation",}
 
int ksinv_t2prep_rftype_refoc = KSINV_RF_STD with {KSINV_RF_STD, KSINV_RF_ADIABATIC, KSINV_RF_STD, VIS, "RF type (0:Std 1:Adiabatic)",}
 
float ksinv_slthickfact_exc = 1.0 with {0, KSINV_MAXTHICKFACT, 1.0, VIS, "Inversion sl.thick / opslthick factor",}
 
KS_MAT4x4 Mphysical_inversion = KS_MAT4x4_IDENTITY
 
KSSPSAT_SEQUENCE ksspsat [KSSPSAT_MAXNUMSAT] = {KSSPSAT_INIT_SEQUENCE}
 
KSSPSAT_PARAMS ksspsat_params = KSSPSAT_INIT_PARAMS
 
int ksspsat_flag = KSSPSAT_OFF with {KSSPSAT_OFF, KSSPSAT_EXPLICIT, KSSPSAT_OFF, VIS, "flag for ksspsat (0:Off 1:Implicit 2:Explicit)",}
 
float ksspsat_flip = KSSPSAT_DEFAULT_FLIP with {0, 360, KSSPSAT_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}
 
int ksspsat_rftype = KSSPSAT_RF_COMPLEX with {KSSPSAT_RF_STD, KSSPSAT_RF_COMPLEX, KSSPSAT_RF_COMPLEX, VIS, "0: SLR Sat 1: Complex Sat",}
 
float ksspsat_spoilerscale = KSSPSAT_DEFAULT_SPOILERSCALE with {0.0, 20.0, KSSPSAT_DEFAULT_SPOILERSCALE, VIS, "scaling of spoiler gradient area",}
 
int ksspsat_spoilallaxes = KSSPSAT_DEFAULT_SPOILALLAXES with {0, 1, KSSPSAT_DEFAULT_SPOILALLAXES, VIS, "apply spoiler on all axes",}
 
int ksspsat_ssi_time = KSSPSAT_DEFAULT_SSITIME with {10, 20000, KSSPSAT_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}
 
int ksspsat_debug = 0 with {0, 1, 0, VIS, "KSSpSat debug flag",}
 
int ksspsat_oblmethod = PSD_OBL_RESTRICT with {PSD_OBL_RESTRICT, PSD_OBL_OPTIMAL, PSD_OBL_RESTRICT, VIS, "obl. grad optimization for sat",}
 

Detailed Description

Macro Definition Documentation

◆ KSCHEMSAT_MODULE_LOADED

#define KSCHEMSAT_MODULE_LOADED   /* can be used to check whether the KSChemsat module has been included in a main psd */

◆ KSCHEMSAT_DEFAULT_FLIP

#define KSCHEMSAT_DEFAULT_FLIP   95

◆ KSCHEMSAT_DEFAULT_SINCRF_BW_15T

#define KSCHEMSAT_DEFAULT_SINCRF_BW_15T   150 /* for 1.5T */

◆ KSCHEMSAT_DEFAULT_SINCRF_BW_3T

#define KSCHEMSAT_DEFAULT_SINCRF_BW_3T   300 /* for 3T */

◆ KSCHEMSAT_DEFAULT_SINCRF_TBP

#define KSCHEMSAT_DEFAULT_SINCRF_TBP   4

◆ KSCHEMSAT_DEFAULT_SPOILERAREA

#define KSCHEMSAT_DEFAULT_SPOILERAREA   5000

◆ KSCHEMSAT_DEFAULT_SSITIME

#define KSCHEMSAT_DEFAULT_SSITIME   1000 /* try to reduce this value */

◆ KSCHEMSAT_INIT_PARAMS

◆ KSCHEMSAT_INIT_SEQUENCE

#define KSCHEMSAT_INIT_SEQUENCE   {{0,0,NULL,sizeof(KSCHEMSAT_SEQUENCE)}, KS_INIT_SEQ_CONTROL, KSCHEMSAT_INIT_PARAMS, KS_INIT_RF, KS_INIT_TRAP}

◆ KSINV_MODULE_LOADED

#define KSINV_MODULE_LOADED   /* can be used to check whether the KSInversion module has been included in a main psd */

◆ KSINV_DEFAULT_FLIP

#define KSINV_DEFAULT_FLIP   180

◆ KSINV_DEFAULT_SPOILERAREA

#define KSINV_DEFAULT_SPOILERAREA   5000

◆ KSINV_DEFAULT_SSITIME

#define KSINV_DEFAULT_SSITIME   1000 /* try to reduce this value */

◆ KSINV_DEFAULT_STARTPOS

#define KSINV_DEFAULT_STARTPOS   100

◆ KSINV_FILLTR_SSITIME

#define KSINV_FILLTR_SSITIME   1000 /* try to reduce this value */

◆ KSINV_MINTR_T2FLAIR

#define KSINV_MINTR_T2FLAIR   8000000 /* default minTR [us] for T2FLAIR, 8 [s] */

◆ KSINV_MINTR_T1FLAIR

#define KSINV_MINTR_T1FLAIR   1300000 /* default minTR [us] for T1FLAIR, 1.3 [s] */

◆ KSINV_MAXTR_T1FLAIR

#define KSINV_MAXTR_T1FLAIR   2500000 /* default maxTR [us] for T1FLAIR, 2.5 [s] */

◆ KSINV_MAXTHICKFACT

#define KSINV_MAXTHICKFACT   3.0 /* how much the inversion slice thickness may increase over opslthick */

◆ KSINV_MAXTHICKFACT_T1FLAIR

#define KSINV_MAXTHICKFACT_T1FLAIR   1.5

◆ T1_CSF_3T

#define T1_CSF_3T   4500

◆ T1_CSF_1_5T

#define T1_CSF_1_5T   3600

◆ T1_GM_3T

#define T1_GM_3T   1400

◆ T1_GM_1_5T

#define T1_GM_1_5T   1100

◆ T1_WM_3T

#define T1_WM_3T   750

◆ T1_WM_1_5T

#define T1_WM_1_5T   600

◆ T1_FAT_3T

#define T1_FAT_3T   340

◆ T1_FAT_1_5T

#define T1_FAT_1_5T   260

◆ KSINV_INIT_PARAMS

◆ KSINV_INIT_SEQUENCE

◆ KSINV_PIUSE

#define KSINV_PIUSE (   o1,
  o2,
  o3,
  o4 
)
Value:
({\
use_ir1_mode = use ## o1;\
use_ir1_t1 = use ## o2;\
use_ir2_mode = use ## o3;\
use_ir2_t1 = use ## o4;\
})

◆ KSINV_OPUSER_VALS

#define KSINV_OPUSER_VALS (   o1,
  o2,
  o3,
  o4 
)
Value:
({\
ksinv1_mode = &opuser ## o1;\
ksinv1_t1value = &opuser ## o2;\
ksinv2_mode = &opuser ## o3;\
ksinv2_t1value = &opuser ## o4;\
})

◆ KSINV_OPUSER_STRUCTS

#define KSINV_OPUSER_STRUCTS (   o1,
  o2,
  o3,
  o4 
)
Value:
({\
_ksinv1_mode = &_opuser ## o1;\
_ksinv1_t1value = &_opuser ## o2;\
_ksinv2_mode = &_opuser ## o3;\
_ksinv2_t1value = &_opuser ## o4;\
})

◆ KSINV_EVAL

#define KSINV_EVAL (   sptr,
  o1,
  o2,
  o3,
  o4 
)
Value:
({\
KSINV_PIUSE(o1, o2, o3, o4);\
KSINV_OPUSER_VALS(o1, o2, o3, o4);\
KSINV_OPUSER_STRUCTS(o1, o2, o3, o4);\
ksinv_eval(sptr, NULL);\
})

C-macro assigning four UserCV slots and then calling ksinv_eval()

Parameters
[in,out]sptrPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]o1A number (not a variable) between 0 and 35 corresponding to the first UserCV used
[in]o2A number (not a variable) between 0 and 35 corresponding to the second UserCV used
[in]o3A number (not a variable) between 0 and 35 corresponding to the third UserCV used
[in]o4A number (not a variable) between 0 and 35 corresponding to the fourth UserCV used

◆ KSINV_EVAL_CUSTOMRF

#define KSINV_EVAL_CUSTOMRF (   sptr,
  rfptr,
  o1,
  o2,
  o3,
  o4 
)
Value:
({\
KSINV_PIUSE(o1, o2, o3, o4);\
KSINV_OPUSER_VALS(o1, o2, o3, o4);\
KSINV_OPUSER_STRUCTS(o1, o2, o3, o4);\
ksinv_eval(sptr, rfptr);\
})

◆ KSSPSAT_MODULE_LOADED

#define KSSPSAT_MODULE_LOADED   /* can be used to check whether the KSSpsat module has been included in a main psd */

◆ KSSPSAT_DEFAULT_FLIP

#define KSSPSAT_DEFAULT_FLIP   95

◆ KSSPSAT_DEFAULT_SPOILERSCALE

#define KSSPSAT_DEFAULT_SPOILERSCALE   5.0

◆ KSSPSAT_DEFAULT_SPOILALLAXES

#define KSSPSAT_DEFAULT_SPOILALLAXES   1

◆ KSSPSAT_DEFAULT_SSITIME

#define KSSPSAT_DEFAULT_SSITIME   1000 /* try to reduce this value */

◆ KSSPSAT_EXPLICITSAT_DISABLED

#define KSSPSAT_EXPLICITSAT_DISABLED   9990.0 /* Set by UI on MR-scanner */

◆ KSSPSAT_IMPLICITSAT_DISABLED

#define KSSPSAT_IMPLICITSAT_DISABLED   9999.0 /* Set by UI on MR-scanner */

◆ KSSPSAT_INIT_VOLBORDER

#define KSSPSAT_INIT_VOLBORDER   {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}

◆ KSSPSAT_INIT_LOC

#define KSSPSAT_INIT_LOC   {DEFAULT_AXIAL_SCAN_INFO, 0, KS_NOTSET, KSSPSAT_OFF}

◆ KSSPSAT_INIT_PARAMS

◆ KSSPSAT_INIT_SEQUENCE

#define KSSPSAT_INIT_SEQUENCE   {{0,0,NULL,sizeof(KSSPSAT_SEQUENCE)}, KS_INIT_SEQ_CONTROL, KSSPSAT_INIT_LOC, KS_INIT_SELRF}

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
KSCHEMSAT_OFF 
KSCHEMSAT_FAT 
KSCHEMSAT_WATER 
Definition: KSChemSat.e:41
Definition: KSChemSat.e:41
Definition: KSChemSat.e:41

◆ anonymous enum

anonymous enum
Enumerator
KSCHEMSAT_RF_STD 
KSCHEMSAT_RF_SINC 
Definition: KSChemSat.e:42
Definition: KSChemSat.e:42

◆ anonymous enum

anonymous enum
Enumerator
KSINV_OFF 
KSINV_IR_SIMPLE 
KSINV_IR_SLICEAHEAD 
KSINV_FLAIR_BLOCK 
KSINV_FLAIR_T2PREP_BLOCK 
Definition: KSInversion.e:45
Definition: KSInversion.e:45
Definition: KSInversion.e:45
Definition: KSInversion.e:45
Definition: KSInversion.e:45

◆ anonymous enum

anonymous enum
Enumerator
KSINV_RF_STD 
KSINV_RF_ADIABATIC 
KSINV_RF_CUSTOM 
Definition: KSInversion.e:46
Definition: KSInversion.e:46
Definition: KSInversion.e:46

◆ KSINV_LOOP_MODE

Enumerator
KSINV_LOOP_NORMAL 
KSINV_LOOP_DUMMY 
KSINV_LOOP_SLICEAHEAD_FIRST 
KSINV_LOOP_SLICEAHEAD_LAST 
KSINV_LOOP_MODE
Definition: KSInversion.e:47
Definition: KSInversion.e:47
Definition: KSInversion.e:47
Definition: KSInversion.e:47
Definition: KSInversion.e:47

◆ anonymous enum

anonymous enum
Enumerator
KSSPSAT_OFF 
KSSPSAT_IMPLICIT 
KSSPSAT_EXPLICIT 
Definition: KSSpSat.e:41
Definition: KSSpSat.e:41
Definition: KSSpSat.e:41

◆ anonymous enum

anonymous enum
Enumerator
KSSPSAT_1 
KSSPSAT_2 
KSSPSAT_3 
KSSPSAT_4 
KSSPSAT_5 
KSSPSAT_6 
KSSPSAT_MAXNUMSAT 
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42

◆ anonymous enum

anonymous enum
Enumerator
KSSPSAT_NEG 
KSSPSAT_POS 
KSSPSAT_HAD 
KSSPSAT_PARA 
Definition: KSSpSat.e:43
Definition: KSSpSat.e:43
Definition: KSSpSat.e:43
Definition: KSSpSat.e:43

◆ anonymous enum

anonymous enum
Enumerator
KSSPSAT_RF_STD 
KSSPSAT_RF_COMPLEX 
KSSPSAT_RF_MAXRFTYPES 
Definition: KSSpSat.e:44
Definition: KSSpSat.e:44
Definition: KSSpSat.e:44

Function Documentation

◆ kschemsat_pg()

STATUS kschemsat_pg ( KSCHEMSAT_SEQUENCE kschemsat)

The kschemsat (fatsat) pulse sequence module

This is the fatsat sequence module in kschemsat.e using the sequence objects in KSCHEMSAT_SEQUENCE with the sequence module name "kschemsat" (= kschemsat.seqctrl.description). On HOST, the minimum duration of the sequence module is set by ks_eval_seqctrl_setminduration().

Parameters
[in,out]kschemsatPointer to KSCHEMSAT_SEQUENCE
Return values
STATUSSUCCESS or FAILURE
320  {
321  STATUS status;
323  loc.pos = RUP_GRD(KS_RFSSP_PRETIME + 32);
324 
325  /* return early if sat mode is off */
327  return SUCCESS;
328  }
329 
330 #ifdef IPG
331  /* TGT (IPG) only: return early if sequence module duration is zero */
332  if (kschemsat->seqctrl.duration == 0)
333  return SUCCESS;
334 #endif
335 
336  /* RF */
337  status = ks_pg_rf(&kschemsat->rf, loc, &kschemsat->seqctrl);
338  if (status != SUCCESS) return status;
339 
340  loc.pos += kschemsat->rf.rfwave.duration;
341 
342  /* Y spoiler */
343  loc.board = YGRAD;
344  status = ks_pg_trap(&kschemsat->spoiler, loc, &kschemsat->seqctrl);
345  if (status != SUCCESS) return status;
346 
347  /* Z spoiler */
348  loc.board = ZGRAD;
349  status = ks_pg_trap(&kschemsat->spoiler, loc, &kschemsat->seqctrl);
350  if (status != SUCCESS) return status;
351 
352  loc.pos += kschemsat->spoiler.duration;
353 
354  /*******************************************************************************************************
355  * Set the minimal sequence duration (ksspsat->seqctrl.min_duration) by calling
356  * ks_eval_seqctrl_setminduration()
357  *******************************************************************************************************/
358 
359  /* make sure we are divisible by GRAD_UPDATE_TIME (4us) */
360  loc.pos = RUP_GRD(loc.pos);
361 
362 #ifdef HOST_TGT
363  /* HOST only: Sequence duration (kschemsat->seqctrl.ssi_time must be > 0 and is added to kschemsat->seqctrl.min_duration in ks_eval_seqctrl_setminduration()
364  if kschemsat->params.satmode = KSCHEMSAT_OFF, then 2nd arg will be zero, making both kschemsat->seqctrl.min_duration and .duration = 0 */
366  ks_eval_seqctrl_setminduration(&kschemsat->seqctrl, loc.pos); /* loc.pos now corresponds to the end of last gradient in the sequence */
367 #endif
368 
369  return SUCCESS;
370 
371 } /* kschemsat_pg() */
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
KSCHEMSAT_PARAMS params
Definition: KSChemSat.e:72
int pos
Definition: KSFoundation.h:389
int board
Definition: KSFoundation.h:388
int duration
Definition: KSFoundation.h:1135
Definition: KSChemSat.e:41
KS_TRAP spoiler
Definition: KSChemSat.e:74
int satmode
Definition: KSChemSat.e:56
KS_WAVE rfwave
Definition: KSFoundation.h:949
STATUS ks_pg_rf(KS_RF *rf, KS_SEQLOC loc, KS_SEQ_CONTROL *ctrl) WARN_UNUSED_RESULT
Places a KS_RF sequence object on a board at some position in the pulse sequence
Definition: KSFoundation_common.c:2049
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 ssi_time
Definition: KSChemSat.e:63
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
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:208
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71
KS_RF rf
Definition: KSChemSat.e:73
int duration
Definition: KSFoundation.h:585
int duration
Definition: KSFoundation.h:668
#define KS_RFSSP_PRETIME
Definition: KSFoundation.h:152

◆ kschemsat_init_params()

void kschemsat_init_params ( KSCHEMSAT_PARAMS params)

Resets the KSCHEMSAT_PARAMS struct (arg 1) to KSCHEMSAT_INIT_PARAMS

Parameters
[out]paramsPointer to the kschemsat params struct used to steer the behavior of this fatsat sequence module
Returns
void
124  {
126  *params = defparams;
127 }
#define KSCHEMSAT_INIT_PARAMS
Definition: KSChemSat.e:65
typedef struct holding steering parameters for KSChemSat
Definition: KSChemSat.e:55

◆ kschemsat_init_sequence()

void kschemsat_init_sequence ( KSCHEMSAT_SEQUENCE kschemsat)

Resets the KSCHEMSAT_SEQUENCE struct (arg 1) to KSCHEMSAT_INIT_SEQUENCE

As KSCHEMSAT_INIT_SEQUENCE contains KSCHEMSAT_PARAMS, which sets the field .satmode = KSCHEMSAT_OFF, calling kschemsat_init_sequence() will disable the kschemsat sequence module (i.e. turn off fatsat)

Parameters
[out]kschemsatPointer to KSCHEMSAT_SEQUENCE
Returns
void
142  {
144  *kschemsat = defseq;
145  strcpy(kschemsat->seqctrl.description, "kschemsat");
146 } /* kschemsat_init_sequence() */
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
#define KSCHEMSAT_INIT_SEQUENCE
Definition: KSChemSat.e:76
typedef struct holding all information about the KSChemSat sequence module incl. all gradients and wa...
Definition: KSChemSat.e:69
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71

◆ kschemsat_eval_copycvs()

void kschemsat_eval_copycvs ( KSCHEMSAT_PARAMS params)

Copy CVs into a common params struct (KSCHEMSAT_PARAMS) used to steer this sequence module

Parameters
[out]paramsPointer to the kschemsat params struct used to steer the behavior of this fatsat sequence module
Returns
void
159  {
160 
161  params->satmode = kschemsat_flag;
162 
163  /* RF */
164  params->flip = kschemsat_flip;
165  params->rfoffset = kschemsat_rfoffset;
166  params->rftype = kschemsat_rftype;
167  if (params->rftype == KSCHEMSAT_RF_SINC) {
168  params->sincrf_bw = kschemsat_sinc_bw;
169  params->sincrf_tbp = kschemsat_sinc_tbp;
170  } else {
171  params->sincrf_bw = KS_NOTSET;
172  params->sincrf_tbp = KS_NOTSET;
173  }
174 
175  /* Spoiler */
177 
178  /* SSI time */
179  params->ssi_time = kschemsat_ssi_time;
180 
181 } /* kschemsat_eval_copycvs() */
float spoilerarea
Definition: KSChemSat.e:62
#define KS_NOTSET
Definition: KSFoundation.h:103
int kschemsat_rftype
Definition: KSChemSat.e:101
int rfoffset
Definition: KSChemSat.e:58
int rftype
Definition: KSChemSat.e:59
int kschemsat_sinc_bw
Definition: KSChemSat.e:102
int kschemsat_sinc_tbp
Definition: KSChemSat.e:103
Definition: KSChemSat.e:42
int kschemsat_ssi_time
Definition: KSChemSat.e:106
int sincrf_bw
Definition: KSChemSat.e:60
int satmode
Definition: KSChemSat.e:56
float kschemsat_spoilerarea
Definition: KSChemSat.e:105
float kschemsat_flip
Definition: KSChemSat.e:100
int sincrf_tbp
Definition: KSChemSat.e:61
int kschemsat_rfoffset
Definition: KSChemSat.e:104
int ssi_time
Definition: KSChemSat.e:63
float flip
Definition: KSChemSat.e:57
int kschemsat_flag
Definition: KSChemSat.e:99

◆ kschemsat_eval_setupobjects()

STATUS kschemsat_eval_setupobjects ( KSCHEMSAT_SEQUENCE kschemsat)

Sets up the sequence objects for the chemsat sequence module (KSCHEMSAT_SEQUENCE kschemsat)

This fatsat sequence module consists of an RF pulse (selectable via .params.rftype and a spoiler trapezoid gradient.

Parameters
[in,out]kschemsatPointer to KSCHEMSAT_SEQUENCE
Return values
STATUSSUCCESS or FAILURE
196  {
197  STATUS status;
198 
199  kschemsat_rfoffset = 0;
200  if (opfat) {
202  kschemsat_rfoffset = -(float) SDL_GetChemicalShift(cffield);
203  } else if (opwater) {
205  } else {
207  }
208 
209  if (cffield == 30000) {
211  } else {
213  }
214 
215  /* Fill in the struct kschemsat.sequence.params based on corresponding kschemsat_*** CVs (see CV section)
216  The CVs should only be used to steer the content of field .params, which in turn should control further decisions */
218 
221  return SUCCESS;
222  }
223 
224  /* RF */
226  /* create a KS_RF using ks_eval_rf_sinc */
228  if (status != SUCCESS) return status;
230  } else {
231  if (cffield == 30000)
232  kschemsat->rf = chemsat_cs3t; /* KSFoundation_GERF.h */
233  else
234  kschemsat->rf = chemsat_csm; /* KSFoundation_GERF.h */
236  if (ks_eval_rf(&kschemsat->rf, "kschemsat_rf") == FAILURE)
237  return FAILURE;
238  }
239  kschemsat->rf.cf_offset = kschemsat->params.rfoffset; /* Exciter offset in Hz */
240 
241  /* ks_print_rf(kschemsat->rf, stderr); fflush(stderr); */
242 
243  /* set up spoiler */
245  status = ks_eval_trap(&kschemsat->spoiler, "kschemsat_spoiler");
246  if (status != SUCCESS) return status;
247 
248 
249  /* setup seqctrl with desired SSI time and zero duration. .min_duration will be set in kschemsat_pg() */
251  strcpy(kschemsat->seqctrl.description, "kschemsat");
252 
253  return SUCCESS;
254 
255 } /* kschemsat_eval_setupobjects() */
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
float spoilerarea
Definition: KSChemSat.e:62
float cf_offset
Definition: KSFoundation.h:942
KSCHEMSAT_PARAMS params
Definition: KSChemSat.e:72
Definition: KSFoundation.h:1954
int role
Definition: KSFoundation.h:939
int rfoffset
Definition: KSChemSat.e:58
int rftype
Definition: KSChemSat.e:59
int kschemsat_sinc_bw
Definition: KSChemSat.e:102
Definition: KSChemSat.e:42
float flip
Definition: KSFoundation.h:940
void kschemsat_eval_copycvs(KSCHEMSAT_PARAMS *params)
Copy CVs into a common params struct (KSCHEMSAT_PARAMS) used to steer this sequence module...
Definition: KSChemSat.e:159
DECL_TYPE KS_RF chemsat_cs3t
Definition: KSFoundation_GERF.c:156
int sincrf_bw
Definition: KSChemSat.e:60
#define KSCHEMSAT_DEFAULT_SINCRF_BW_15T
Definition: KSChemSat.e:47
Definition: KSChemSat.e:41
KS_TRAP spoiler
Definition: KSChemSat.e:74
int satmode
Definition: KSChemSat.e:56
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 sincrf_tbp
Definition: KSChemSat.e:61
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
#define KSCHEMSAT_DEFAULT_SINCRF_BW_3T
Definition: KSChemSat.e:48
float area
Definition: KSFoundation.h:582
STATUS ks_eval_rf(KS_RF *rf, const char *const desc) WARN_UNUSED_RESULT
Sets up a KS_RF object
Definition: KSFoundation_host.c:2707
STATUS ks_eval_rf_sinc(KS_RF *rf, const char *const desc, double bw, double tbw, float flip, int wintype) WARN_UNUSED_RESULT
Sets up a KS_RF object with a Sinc pulse shape
Definition: KSFoundation_host.c:2227
int kschemsat_rfoffset
Definition: KSChemSat.e:104
DECL_TYPE KS_RF chemsat_csm
Definition: KSFoundation_GERF.c:153
Definition: KSFoundation.h:1953
float flip
Definition: KSChemSat.e:57
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
void kschemsat_init_sequence(KSCHEMSAT_SEQUENCE *kschemsat)
Resets the KSCHEMSAT_SEQUENCE struct (arg 1) to KSCHEMSAT_INIT_SEQUENCE
Definition: KSChemSat.e:142
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71
KS_RF rf
Definition: KSChemSat.e:73
Definition: KSChemSat.e:41
Definition: KSChemSat.e:41
int kschemsat_flag
Definition: KSChemSat.e:99

◆ kschemsat_eval()

STATUS kschemsat_eval ( KS_SEQ_COLLECTION seqcollection)

Chemsat evaluation function, to be called from the cveval() function of the main sequence

This function calls kschemsat_eval_setupobjects() to design the RF pulse and spoiler for this fatsat sequence module. It then calls kschemsat_pg() to determine the (minimum) sequence module duration. Finally, the sequence module kschemsat is added to the sequence collection struct passed in from the cveval() function of the main sequence.

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
Return values
STATUSSUCCESS or FAILURE
273  {
274  STATUS status;
275 
276  /* N.B.:
277  - UI CV opfat = 1: FatSat (kschemsat_flag = KSCHEMSAT_FAT)
278  - UI CV opwater = 1: WaterSat (kschemsat_flag = KSCHEMSAT_WATER)
279  - UI CV opfat = opwater = 0: Off
280  */
282  if (status != SUCCESS) return status;
283 
284  /* kschemsat_pg() will return early if kschemsat.params.satmode == KSCHEMSAT_OFF => kschemsat.seqctrl.duration = 0 */
285  status = kschemsat_pg(&kschemsat);
286  if (status != SUCCESS) return status;
287 
288  /* ks_eval_addtoseqcollection() will only add to collection if kschemsat.seqctrl.duration > 0 */
290  if (status != SUCCESS) return status;
291 
292  return status;
293 
294 } /* kschemsat_eval() */
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
int kschemsat_pg(KSCHEMSAT_SEQUENCE *chemsat)
The kschemsat (fatsat) pulse sequence module
Definition: KSChemSat.e:320
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 kschemsat_eval_setupobjects(KSCHEMSAT_SEQUENCE *kschemsat)
Sets up the sequence objects for the chemsat sequence module (KSCHEMSAT_SEQUENCE kschemsat)
Definition: KSChemSat.e:196
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KS_SEQ_CONTROL seqctrl
Definition: KSChemSat.e:71

◆ kschemsat_scan_seqstate()

void kschemsat_scan_seqstate ( KSCHEMSAT_SEQUENCE kschemsat)

Sets the current state of all kschemsat sequence objects being part of KSCHEMSAT_SEQUENCE

This function sets the current state of all kschemsat sequence objects being part of KSCHEMSAT_SEQUENCE, incl. gradient amplitude and RF phase changes.

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.

Returns
void
388  {
389 #ifdef IPG
390  static int counter = 0;
391 
392  float rfphase = ks_scan_rf_phase_spoiling(counter++);
393 
394  ks_scan_rf_setphase(&kschemsat->rf, INSTRALL, rfphase);
395 
396 #endif
397 }
KSCHEMSAT_SEQUENCE kschemsat
Definition: KSChemSat.e:89
float ks_scan_rf_phase_spoiling(int counter)
Returns spoiling phase for a given RF counter
Definition: KSFoundation_common.c:3883
void ks_scan_rf_setphase(KS_RF *rf, int instanceno, float rfphase)
Updates the phase of one or all instances of an RF pulse (KS_RF)
Definition: KSFoundation_tgt.c:685
KS_RF rf
Definition: KSChemSat.e:73

◆ ksinv_eval_checkTR_SAR()

STATUS ksinv_eval_checkTR_SAR ( KS_SEQ_COLLECTION seqcollection,
KS_SLICE_PLAN slice_plan,
int(*)(const SCAN_INFO *, int, int, void **)  play_coreslice,
int  core_nargs,
void **  core_args 
)

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

This function first makes sure that the .nseqinstances field for each sequence module in the sequence collection corresponds to the number of times played out in ksinv_scan_sliceloop()

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

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

N.B.: For non-inversion sequences, ks_eval_checkTR_SAR() is used to do the same thing, with the difference that the psd's sliceloop function is used instead of ksinv_scan_sliceloop().

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]slice_planPointer to the KS_SLICE_PLAN struct holding the slice order information
[in]play_coresliceFunction pointer to (the wrapper function to) the coreslice function of the sequence
[in]core_nargsNumber of extra input arguments to the coreslice wrapper function.
[in]core_argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's coreslice function
Return values
STATUSSUCCESS or FAILURE
1853  {
1854  STATUS status;
1855 
1856  /* set all `seqctrl.nseqinstances` to 0 */
1858 
1859  /* set all `seqctrl.nseqinstances` to the number of occurrences */
1860  ksinv_scan_sliceloop(slice_plan, ks_scan_info, 0, &ksinv1, &ksinv2, &ksinv_filltr, KSINV_LOOP_NORMAL, play_coreslice, core_nargs, core_args);
1861 
1862  /* validate TR and check that we are within SAR/hardware limits */
1864  if (status != SUCCESS) return status;
1865 
1866  return SUCCESS;
1867 
1868 } /* ksinv_eval_checkTR_SAR() */
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
STATUS GEReq_eval_checkTR_SAR_calcs(KS_SEQ_COLLECTION *seqcollection, int intended_time)
Checks that sequence modules sum up to TR, honoring SAR/heating limits
Definition: GERequired.e:848
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
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
Definition: KSInversion.e:47
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
void ks_eval_seqcollection_resetninst(KS_SEQ_COLLECTION *seqcollection)
Set the .nseqinstances field of each sequence module (KS_SEQ_CONTROL) equal to 0
Definition: KSFoundation_host.c:4590
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksinv_pg()

STATUS ksinv_pg ( KSINV_SEQUENCE ksinv)

Generation of the waveforms for the sequence objects in a KSINV_SEQUENCE

Two KSINV_SEQUENCE structs are currently declared in KSInversion.e, ksinv1 and ksinv2. By passing each one of them to this function, will generate the actual sequence on TGT. On HOST, the seqctrl.min_duration field is set and used by TI/TR calculations.

Return values
STATUSSUCCESS or FAILURE
1937  {
1938  STATUS status;
1939  KS_SEQLOC loc = KS_INIT_SEQLOC;
1940 
1941 
1942  if (ksinv->params.irmode == KSINV_OFF)
1943  return SUCCESS;
1944 
1945 #ifdef IPG
1946  /* TGT (IPG) only: return early if sequence module duration is zero */
1947  if (ksinv->seqctrl.duration == 0)
1948  return SUCCESS;
1949 #endif
1950 
1951 
1952  loc.pos = ksinv->params.startpos;
1953 
1954  if (loc.pos % GRAD_UPDATE_TIME) {
1955  return ks_error("%s: Start position of RF pulse must be divisible by GRAD_UPDATE_TIME (ksinv->params.rfstartpos = %d)", __FUNCTION__, ksinv->params.startpos);
1956  }
1957  if (loc.pos < KS_RFSSP_PRETIME) {
1958  return ks_error("%s: Start position of RF pulse must be at least %d [us] (ksinv->params.rfstartpos = %d)", __FUNCTION__, KS_RFSSP_PRETIME, ksinv->params.startpos);
1959  }
1960 
1961  /* RF */
1962  if (ksinv_slicecheck){
1963  loc.board = XGRAD;
1964  } else {
1965  loc.board = ZGRAD;
1966  }
1967 
1968 
1969  if (ksinv->params.irmode == KSINV_FLAIR_T2PREP_BLOCK) {
1970 
1971  if (ks_pg_selrf(&ksinv->selrfexc, loc, &ksinv->seqctrl) == FAILURE)
1972  return FAILURE;
1973 
1974  int mag_center_exc = loc.pos + ksinv->selrfexc.grad.ramptime + ksinv->selrfexc.rf.start2iso;
1975 
1976  /* now refocussing pulses*/
1977  /* we make sure that that delta_t_refoc/2 is a multiple of GRAD_UPDATE_TIME using the RUP_GRD function (division results are integer truncated) */
1978  int delta_t_refoc_half = RUP_GRD(ksinv->params.t2prep_TE / ksinv->params.N_Refoc / 2);
1979 
1980  /* first refocusing pulse*/
1981  loc.pos = mag_center_exc + delta_t_refoc_half - ksinv->selrfrefoc.grad.ramptime - ksinv->selrfrefoc.rf.start2iso - ksinv->selrfrefoc.pregrad.duration;
1982  if (ks_pg_selrf(&ksinv->selrfrefoc, loc, &ksinv->seqctrl) == FAILURE)
1983  return FAILURE;
1984  /* all other refocusing pulses*/
1985  int n;
1986  for (n = 1; n < ksinv->params.N_Refoc; n++) {
1987  loc.pos += 2*delta_t_refoc_half;
1988  if (ks_pg_selrf(&ksinv->selrfrefoc, loc, &ksinv->seqctrl) == FAILURE)
1989  return FAILURE;
1990  }
1991 
1992  /***************************************************************************************************
1993  * two different versions
1994  * non adiabatic (+90)-(n*180)-(+90)
1995  * adiabatic (+90)-(n*180)-(-90)-(180)
1996  * the polarity of the flip angle of the flip pulse is set with loc.ampscale
1997  ***************************************************************************************************/
1998 
1999  loc.pos = mag_center_exc + ksinv->params.N_Refoc*delta_t_refoc_half*2 - ksinv->selrfflip.grad.ramptime - ksinv->selrfflip.rf.start2iso - ksinv->selrfflip.pregrad.duration;
2000 
2001  if (ksinv->params.rftype == KSINV_RF_ADIABATIC) {
2002  loc.ampscale = -1;
2003  } else {
2004  loc.ampscale = 1;
2005  }
2006 
2007  if (ks_pg_selrf(&ksinv->selrfflip, loc, &ksinv->seqctrl) == FAILURE)
2008  return FAILURE;
2009 
2010  /* Save absolute time in sequence for moment start, it is important to do that after
2011  ks_pg_selrf(&ksinv->selrfflip, loc, &ksinv->seqctrl) because otherwise ksinv->seqctrl.momentstart would be overwritten as
2012  the "ROLE" of selrfflip is an excitation pulse, there is no ROLE for a flipup pulse yet */
2013  ksinv->seqctrl.momentstart = mag_center_exc;
2014 
2015  loc.ampscale = 1; /* set it back to default */
2016  /* waveform overlap problems between selrfflip and selrfinv on DV25 --> 5*GRAD_UPDATE_TIME safety margin */
2017  loc.pos += ksinv->selrfflip.pregrad.duration + ksinv->selrfflip.grad.duration + 5*GRAD_UPDATE_TIME;
2018 
2019  if (ksinv->params.rftype == KSINV_RF_ADIABATIC) {
2020  if (ks_pg_selrf(&ksinv->selrfinv, loc, &ksinv->seqctrl) == FAILURE)
2021  return FAILURE;
2022  loc.pos += (ksinv->selrfinv.grad.duration > 0) ? ksinv->selrfinv.grad.duration : ksinv->selrfinv.gradwave.duration;
2023  }
2024  } else {
2025 
2026  /* Save absolute time in sequence for moment start */
2027  ksinv->seqctrl.momentstart = loc.pos + ksinv->selrfinv.grad.ramptime + ksinv->selrfinv.rf.start2iso;
2028 
2029  status = ks_pg_selrf(&ksinv->selrfinv, loc, &ksinv->seqctrl);
2030  if (status != SUCCESS) return status;
2031 
2032  loc.pos += (ksinv->selrfinv.grad.duration > 0) ? ksinv->selrfinv.grad.duration : ksinv->selrfinv.gradwave.duration;
2033 
2034  }
2035 
2036  /* Z spoiler */
2037  loc.board = YGRAD;
2038  status = ks_pg_trap(&ksinv->spoiler, loc, &ksinv->seqctrl);
2039  if (status != SUCCESS) return status;
2040  loc.pos += ksinv->spoiler.duration;
2041 
2042 
2043  /*******************************************************************************************************
2044  * Set the minimal sequence duration (ksinv->seqctrl.min_duration) by calling
2045  * ks_eval_seqctrl_setminduration()
2046  *******************************************************************************************************/
2047 
2048  /* make sure we are divisible by GRAD_UPDATE_TIME (4us) */
2049  loc.pos = RUP_GRD(loc.pos);
2050 
2051 #ifdef HOST_TGT
2052  /* On HOST only: Sequence module duration (ksinv->seqctrl.ssi_time must be > 0 and is added to ksinv->seqctrl.min_duration in ks_eval_seqctrl_setminduration()) */
2053  ksinv->seqctrl.ssi_time = ksinv->params.ssi_time;
2054  ks_eval_seqctrl_setminduration(&ksinv->seqctrl, loc.pos); /* loc.pos now corresponds to the end of last gradient in the sequence */
2055 #endif
2056 
2057 
2058  return SUCCESS;
2059 
2060 } /* ksinv_pg() */
KS_TRAP grad
Definition: KSFoundation.h:1491
int start2iso
Definition: KSFoundation.h:944
KS_SELRF selrfinv
Definition: KSInversion.e:102
int pos
Definition: KSFoundation.h:389
KS_WAVE gradwave
Definition: KSFoundation.h:1493
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
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
int board
Definition: KSFoundation.h:388
int t2prep_TE
Definition: KSInversion.e:91
int duration
Definition: KSFoundation.h:1135
int irmode
Definition: KSInversion.e:76
Definition: KSInversion.e:46
float ampscale
Definition: KSFoundation.h:390
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_SELRF selrfflip
Definition: KSInversion.e:105
KS_RF rf
Definition: KSFoundation.h:1485
KS_SELRF selrfexc
Definition: KSInversion.e:104
int ksinv_slicecheck
Definition: KSInversion.e:162
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 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
Definition: KSInversion.e:45
KS_SELRF selrfrefoc
Definition: KSInversion.e:106
KSINV_PARAMS params
Definition: KSInversion.e:101
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:208
int duration
Definition: KSFoundation.h:585
Definition: KSInversion.e:45
KS_TRAP spoiler
Definition: KSInversion.e:103
int rftype
Definition: KSInversion.e:80
int ramptime
Definition: KSFoundation.h:583
int duration
Definition: KSFoundation.h:668
int N_Refoc
Definition: KSInversion.e:90
int startpos
Definition: KSInversion.e:83
int ssi_time
Definition: KSInversion.e:86
#define KS_RFSSP_PRETIME
Definition: KSFoundation.h:152

◆ ksinv_scan_sliceloop()

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(*)(const SCAN_INFO *, int, int, void **)  play_coreslice,
int  core_nargs,
void **  core_args 
)

Plays out slice_plan.nslices_per_pass slices corresponding to one TR for inversion psds

This function should replace the sliceloop function of a 2D psd when inversion is enabled. It will take over the sequence timing for one TR by playing out the inversion sequence module(s) and other sequence modules in an order that is subject to the inversion mode (ksinvX.params.irmode). The non-inversion sequence modules should be played out together in a 'core slice' function of the psd. This core slice function should have a wrapper function with standardized input arguments that conmplies with the function pointer (and core_nargs, core_args) passed to this function.

Parameters
[in]slice_planPointer to the slice plan (KS_SLICE_PLAN) set up earlier using ks_calc_sliceplan() or similar
[in]slice_positionsPointer to the SCAN_INFO array corresponding to the slice locations (typically ks_scan_info)
[in]passindxPass index in range [0, ks_slice_plan.npasses - 1]
[in]ksinv1Pointer to KSINV_SEQUENCE corresponding to the 1st (or only) inversion. Cannot be NULL
[in]ksinv2Pointer to KSINV_SEQUENCE corresponding to an optional 2nd inversion. May be NULL
[in]ksinv_filltrPointer to KS_SEQ_CONTROL for fillTR sequence for FLAIR block modes. May be NULL
[in]ksinv_loop_modeIf KSINV_LOOP_DUMMY, this function will pass in KS_NOTSET (-1) as the 2nd argument to 'play_coreslice'. For this to work, the play_coreslice() function (usually the main sequence's coreslice), must check if it's 2nd arg is KS_NOTSET, and if so shut off data collection in loaddab() KSINV_LOOP_NORMAL: Slice excitation ON, Data acq. ON KSINV_LOOP_DUMMY: Slice excitation ON, Data acq. OFF KSINV_LOOP_SLICEAHEAD_FIRST: Slice excitation ON for IR, OFF for coreslice, Data acq. OFF KSINV_LOOP_SLICEAHEAD_LAST: Slice excitation OFF for IR, ON for coreslice, Data acq. ON
[in]play_coresliceFunction pointer to (the wrapper function to) the coreslice function of the sequence
[in]core_nargsNumber of extra input arguments to the coreslice wrapper function.
[in]core_argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's coreslice function
Return values
slicelooptimeTime taken in [us] to play out slice_plan.nslices_per_pass slices
2259  {
2260  int time = 0;
2261  int i, sltimeinpass;
2262  int slloc, sltime_adjusted;
2263  const SCAN_INFO *slpos;
2264 
2265  if (ksinv1 == NULL) {
2266  ks_error("%s: 4th arg cannot be NULL", __FUNCTION__);
2267  return KS_NOTSET;
2268  }
2269  if (ksinv1->params.irmode == KSINV_OFF) {
2270  return 0; /* if the IR mode for the 1st IR is off, return quietly */
2271  }
2272  if (slice_plan == NULL) {
2273  ks_error("%s: 1st arg cannot be NULL", __FUNCTION__);
2274  return KS_NOTSET;
2275  }
2276  if (slice_positions == NULL) {
2277  ks_error("%s: 2nd arg cannot be NULL", __FUNCTION__);
2278  return KS_NOTSET;
2279  }
2280 
2281  if (play_coreslice == NULL) {
2282  ks_error("%s: 7th arg must be a function pointer to the coreslice function", __FUNCTION__);
2283  return KS_NOTSET;
2284  }
2285 
2286 
2288  /* For classic T2-FLAIR, we often end up with 2 sets of FLAIR+core per TR
2289  Here is a generalization, where number of sets is equal to:
2290  CEIL_DIV(slice_plan->nslices_per_pass, ksinv1->params.nflairslices), where slice_plan->nslices_per_pass = CEIL_DIV(slice_plan->nslices, slice_plan->npasses)
2291  */
2292 
2293  /* make sure nflairslices > 0, or else we will be stuck here as sltimeinpass will remain at 0 forever */
2294  if (ksinv1->params.nflairslices <= 0) {
2295  ks_error("%s: ksinv1.params.nflairslices must be > 0", __FUNCTION__);
2296  return -1;
2297  }
2298 
2299  sltimeinpass = 0;
2300 
2301  while (sltimeinpass < slice_plan->nslices_per_pass) {
2302 
2303  /*--------- 1st inversion sequence module as FLAIR block -----------*/
2304  for (i = 0; i < ksinv1->params.nflairslices; i++) {
2305  slloc = ks_scan_getsliceloc(slice_plan, passindx, sltimeinpass + i);
2306  slpos = (slloc != KS_NOTSET) ? &slice_positions[slloc] : NULL;
2307  time += ksinv_scan_irslice(ksinv1, slpos /* if NULL, shut off RF */);
2308  }
2309 
2310  for (i = 0; (i < ksinv1->params.nflairslices) && (sltimeinpass + i < slice_plan->nslices_per_pass); i++) {
2311  slloc = ks_scan_getsliceloc(slice_plan, passindx, sltimeinpass + i);
2312  slpos = (slloc != KS_NOTSET) ? &slice_positions[slloc] : NULL;
2313 
2314  if (ksinv2 != NULL) {
2315  /*--------- optional 2nd inversion sequence module (DIR mode) attached to each coreslice playout -----------*/
2316  time += ksinv_scan_irslice(ksinv2, slpos /* if NULL, shut off RF */);
2317  }
2318 
2319  /*--------- "coreslice": main sequence module (may include e.g. GRx Sat, FatSat etc.) -----------*/
2320  time += play_coreslice(
2321  slpos, /* if NULL, shut off RF. The coreslice function must also shut data acquisition off regardless of next arg */
2322  (ksinv_loop_mode == KSINV_LOOP_DUMMY) ? KS_NOTSET : (sltimeinpass + i), /* if KS_NOTSET (-1), shut off data acquisition */
2323  core_nargs, core_args);
2324  }
2325 
2326  sltimeinpass += ksinv1->params.nflairslices;
2327 
2328  if (ksinv_filltr != NULL) {
2329  /*--------- fillTR sequence module (to fill up to manual TR in CEIL_DIV(nslices_per_pass, ksinv1->params.nflairslices) chunks) -----------*/
2331  ks_plot_slicetime(ksinv_filltr, 1, NULL, KS_NOTSET, KS_PLOT_NO_EXCITATION); /* Add a filler to slicetime plot */
2332  }
2333 
2334  } /* while */
2335 
2336 
2337  } else {
2338 
2339  int sltime_start = (ksinv_loop_mode == KSINV_LOOP_SLICEAHEAD_FIRST) ? (slice_plan->nslices_per_pass - ksinv1->params.nslicesahead) : 0;
2340 
2341  for (sltimeinpass = sltime_start; sltimeinpass < slice_plan->nslices_per_pass; sltimeinpass++) {
2342 
2343  /*--------- 1st inversion sequence module -----------*/
2345  sltime_adjusted = (sltimeinpass + ksinv1->params.nslicesahead) % slice_plan->nslices_per_pass;
2346  slloc = ks_scan_getsliceloc(slice_plan, passindx, sltime_adjusted);
2347  slpos = (slloc != KS_NOTSET) ? &slice_positions[slloc] : NULL;
2348  slpos = ((ksinv_loop_mode == KSINV_LOOP_SLICEAHEAD_LAST) && (sltime_adjusted < ksinv1->params.nslicesahead)) ? NULL : slpos;
2349  time += ksinv_scan_irslice(ksinv1, slpos /* if NULL, shut off RF */);
2350  }
2351 
2352  /*--------- 2nd inversion sequence module -----------*/
2354  sltime_adjusted = (sltimeinpass + ksinv2->params.nslicesahead) % slice_plan->nslices_per_pass;
2355  slloc = ks_scan_getsliceloc(slice_plan, passindx, sltime_adjusted);
2356  slpos = (slloc != KS_NOTSET) ? &slice_positions[slloc] : NULL;
2357  time += ksinv_scan_irslice(ksinv2, slpos /* if NULL, shut off RF */);
2358  }
2359 
2360  /*--------- "coreslice": main sequence module (may include e.g. GRx Sat, FatSat etc.) -----------*/
2361  slloc = ks_scan_getsliceloc(slice_plan, passindx, sltimeinpass);
2362  slpos = (slloc != KS_NOTSET) ? &slice_positions[slloc] : NULL;
2363  slpos = (ksinv_loop_mode == KSINV_LOOP_SLICEAHEAD_FIRST) ? NULL : slpos;
2364  time += play_coreslice(
2365  slpos, /* if NULL, shut off RF. The coreslice function must also shut data acquisition off regardless of next arg */
2366  (ksinv_loop_mode == KSINV_LOOP_DUMMY) ? KS_NOTSET : sltimeinpass, /* if KS_NOTSET (-1), shut off data acquisition */
2367  core_nargs,
2368  core_args);
2369 
2370  } /* slice in pass */
2371 
2372  } /* else (not FLAIR-block) */
2373 
2374  /* Turn on RF again so that it shows up in the plot */
2375  if (ksinv1 != NULL) {
2376  ksinv_scan_seqstate(ksinv1, &slice_positions[0]);
2377  }
2378  if (ksinv2 != NULL) {
2379  ksinv_scan_seqstate(ksinv2, &slice_positions[0]);
2380  }
2381 
2382  return time;
2383 
2384 } /* ksinv_scan_sliceloop() */
#define KS_NOTSET
Definition: KSFoundation.h:103
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int32_t i
Definition: KSFoundation_tgt.c:1389
Definition: KSInversion.e:45
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
Definition: KSInversion.e:45
Definition: KSInversion.e:47
int nslicesahead
Definition: KSInversion.e:84
int irmode
Definition: KSInversion.e:76
STATUS ksinv_scan_seqstate(KSINV_SEQUENCE *ksinv, const SCAN_INFO *slice_info)
Sets the current state of a KSINV_SEQUENCE during scanning
Definition: KSInversion.e:2110
int nslices_per_pass
Definition: KSFoundation.h:1353
Definition: KSInversion.e:47
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1368
Definition: KSFoundation.h:336
int passindx
Definition: ksfse_implementation.e:2849
int nflairslices
Definition: KSInversion.e:85
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
Definition: KSInversion.e:45
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
int ksinv_scan_irslice(KSINV_SEQUENCE *ksinv, const SCAN_INFO *slice_pos)
Plays out one inversion slice in real time during scanning
Definition: KSInversion.e:2178
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
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45
Definition: KSInversion.e:45
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
Definition: KSInversion.e:47

◆ ksinv_init_params()

void ksinv_init_params ( KSINV_PARAMS params)

Resets the KSINV_PARAMS struct (arg 1) to KSINV_INIT_PARAMS

Parameters
[out]paramsPointer to the ksinv params struct used to steer the behavior of this inversion sequence module
Returns
void
198  {
199  KSINV_PARAMS defparams = KSINV_INIT_PARAMS;
200  *params = defparams;
201 } /* ksinv_init_params() */
typedef struct holding steering parameters for KSInversion
Definition: KSInversion.e:75
#define KSINV_INIT_PARAMS
Definition: KSInversion.e:94

◆ ksinv_init_sequence()

void ksinv_init_sequence ( KSINV_SEQUENCE ksinv)

Resets the KSINV_SEQUENCE struct (arg 1) to KSINV_INIT_SEQUENCE

As KSINV_INIT_SEQUENCE contains KSINV_PARAMS, which sets the field .irmode = KSINV_OFF, calling ksinv_init_sequence() will disable the ksinversion sequence module (i.e. turn off inversion)

Parameters
[out]ksinvPointer to KSINV_SEQUENCE
Returns
void
216  {
218  *ksinv = defseq;
219  ksinv_init_params(&ksinv->params);
220 } /* ksinv_init_sequence() */
void ksinv_init_params(KSINV_PARAMS *params)
Resets the KSINV_PARAMS struct (arg 1) to KSINV_INIT_PARAMS
Definition: KSInversion.e:198
#define KSINV_INIT_SEQUENCE
Definition: KSInversion.e:108
typedef struct holding all information about the KSInversion sequence module incl. all gradients and waveforms
Definition: KSInversion.e:98
KSINV_PARAMS params
Definition: KSInversion.e:101

◆ ksinv_eval_copycvs()

void ksinv_eval_copycvs ( KSINV_PARAMS params,
int  mode 
)

Copy CVs into a common params struct (KSINV_PARAMS) used to steer this sequence module

Parameters
[out]paramsPointer to the ksinv params struct used to steer the behavior of this inversion sequence module
[in]modeInversion mode, one of: KSINV_OFF, KSINV_IR_SIMPLE, KSINV_IR_SLICEAHEAD, KSINV_FLAIR_BLOCK
Returns
void
234  {
235 
236  ksinv_init_params(params);
237 
238  params->irmode = mode;
239 
240  if (params->irmode != KSINV_OFF) {
241  params->flip = ksinv_flip;
242  if (KS_3D_SELECTED) {
243  params->slthick = opvthick * ksinv_slthickfact;
244  } else {
245  params->slthick = opslthick * ksinv_slthickfact;
246  }
247  params->rfoffset = ksinv_rfoffset;
248  params->rftype = ksinv_rftype;
249  params->spoilerarea = ksinv_spoilerarea;
250  if (params->irmode == KSINV_IR_SLICEAHEAD) {
251  params->approxti = ksinv_approxti; /* Only applicable for sliceahead mode */
252  } else {
253  params->approxti = FALSE;
254  }
255  params->startpos = RUP_GRD(ksinv_startpos);
256  params->nslicesahead = 0;
257  params->nflairslices = 0;
258 
259  if (params->irmode == KSINV_FLAIR_T2PREP_BLOCK) {
262  params->N_Refoc = ksinv_t2prep_N_Refoc;
263  params->t2prep_TE = ksinv_t2prep_TE;
265  }
266  }
267 
268  /* SSI time */
269  params->ssi_time = ksinv_ssi_time;
270 
271 } /* ksinv_eval_copycvs() */
int ksinv_t2prep_rftype_refoc
Definition: KSInversion.e:178
int rfoffset
Definition: KSInversion.e:79
void ksinv_init_params(KSINV_PARAMS *params)
Resets the KSINV_PARAMS struct (arg 1) to KSINV_INIT_PARAMS
Definition: KSInversion.e:198
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
Definition: KSInversion.e:45
float slthick_exc
Definition: KSInversion.e:89
int t2prep_TE
Definition: KSInversion.e:91
float ksinv_flip
Definition: KSInversion.e:166
int nslicesahead
Definition: KSInversion.e:84
int irmode
Definition: KSInversion.e:76
float ksinv_slthickfact
Definition: KSInversion.e:167
int ksinv_t2prep_TE
Definition: KSInversion.e:177
int rftype_refoc
Definition: KSInversion.e:92
int ksinv_rftype
Definition: KSInversion.e:169
float spoilerarea
Definition: KSInversion.e:81
int ksinv_startpos
Definition: KSInversion.e:171
int nflairslices
Definition: KSInversion.e:85
float flip_exc
Definition: KSInversion.e:88
float slthick
Definition: KSInversion.e:78
float ksinv_slthickfact_exc
Definition: KSInversion.e:179
Definition: KSInversion.e:45
int ksinv_approxti
Definition: KSInversion.e:163
float ksinv_spoilerarea
Definition: KSInversion.e:170
int ksinv_t2prep_exc_flip
Definition: KSInversion.e:175
int ksinv_t2prep_N_Refoc
Definition: KSInversion.e:176
int ksinv_rfoffset
Definition: KSInversion.e:168
int ksinv_ssi_time
Definition: KSInversion.e:157
Definition: KSInversion.e:45
float opslthick
float flip
Definition: KSInversion.e:77
int rftype
Definition: KSInversion.e:80
int approxti
Definition: KSInversion.e:82
int N_Refoc
Definition: KSInversion.e:90
int startpos
Definition: KSInversion.e:83
int ssi_time
Definition: KSInversion.e:86

◆ ksinv_eval_setuprf()

STATUS ksinv_eval_setuprf ( KSINV_SEQUENCE ksinv,
const char *  suffix,
KS_SELRF custom_selrf 
)

Sets up the RF sequence object for the inversion sequence module (KSINV_SEQUENCE ksinv)

This function is called from ksinv_eval_setupobjects()

Parameters
[in,out]ksinvPointer to a KSINV_SEQUENCE sequence module to be set up
[in]suffixSuffix string to att to "ksinv" for the description of the sequence module
[in,out]custom_selrfOptional pointer to KS_SELRF for custom inversion RF pulse. Pass NULL to use default RF pulses.
Return values
STATUSSUCCESS or FAILURE
288  {
289  STATUS status;
290  char tmpstr[1000];
291 
292  /* if irmode == KSINV_OFF, reset and return */
293  if (ksinv->params.irmode == KSINV_OFF) {
294  ksinv_init_sequence(ksinv);
295  return SUCCESS;
296  }
297 
298  if (custom_selrf != NULL) {
299 
300  ksinv->selrfinv = *custom_selrf;
301  ksinv->params.rftype = KSINV_RF_CUSTOM;
302  return SUCCESS;
303 
304  } else if (ksinv->params.rftype == KSINV_RF_ADIABATIC) {
305 
306  ksinv->selrfinv.rf = adinv_shNvrg5b; /* KSFoundation_GERF.h */
307 
308  } else if (ksinv->params.rftype == KSINV_RF_STD) {
309 
310  ksinv->selrfinv.rf = inv_invI0; /* KSFoundation_GERF.h */
311 
312  } else {
313 
314  return ks_error("%s: invalid RF type (ksinv.params.rftype = %d)", __FUNCTION__, ksinv->params.rftype);
315 
316  }
317 
318  /* N.B. The designed (i.e. nominal) flip angle varies a lot between GE's inversion RF pulses:
319  - adinv_sh3t2: 250 deg.
320  - shNvrg5b: 43.82 deg.
321  - invI0: (non-adiabatic) 178 deg
322  So it is important to set the desired FA now after the 'ksinv->selrfinv.rf =' assignment above.
323  The relation between .selrfinv.rf.flip and .selrfinv.rf.rfpulse.nom_fa can be used internally for RF scaling
324  */
325  ksinv->selrfinv.rf.flip = ksinv->params.flip; /* desired FA */
326  ksinv->selrfinv.rf.cf_offset = ksinv->params.rfoffset; /* Exciter offset in Hz */
327  ksinv->selrfinv.slthick = ksinv->params.slthick;
328  sprintf(tmpstr, "ksinv_selinv%s", suffix);
329 
330  status = ks_eval_selrf(&ksinv->selrfinv, tmpstr);
331  if (status != SUCCESS) return status;
332 
333 
334  return SUCCESS;
335 
336 } /* ksinv_eval_setuprf() */
float cf_offset
Definition: KSFoundation.h:942
KS_SELRF selrfinv
Definition: KSInversion.e:102
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
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int rfoffset
Definition: KSInversion.e:79
int irmode
Definition: KSInversion.e:76
Definition: KSInversion.e:46
float flip
Definition: KSFoundation.h:940
KS_RF rf
Definition: KSFoundation.h:1485
DECL_TYPE KS_RF adinv_shNvrg5b
Definition: KSFoundation_GERF.c:122
Definition: KSInversion.e:46
DECL_TYPE KS_RF inv_invI0
Definition: KSFoundation_GERF.c:128
float slthick
Definition: KSInversion.e:78
KSINV_PARAMS params
Definition: KSInversion.e:101
void ksinv_init_sequence(KSINV_SEQUENCE *ksinv)
Resets the KSINV_SEQUENCE struct (arg 1) to KSINV_INIT_SEQUENCE
Definition: KSInversion.e:216
Definition: KSInversion.e:46
Definition: KSInversion.e:45
float flip
Definition: KSInversion.e:77
int rftype
Definition: KSInversion.e:80
float slthick
Definition: KSFoundation.h:1487

◆ ksinv_eval_setupt2prep()

STATUS ksinv_eval_setupt2prep ( KSINV_SEQUENCE ksinv)
339  {
340  STATUS status;
341  status = SUCCESS;
342 
343  ksinv->selrfexc.rf = exc_ssfse90new;
344  ksinv->selrfexc.rf.flip = ksinv->params.flip_exc;
345  ksinv->selrfexc.slthick = ksinv->params.slthick_exc;
346  status = ks_eval_selrf(&ksinv->selrfexc, "ksinv_T2prep_exc");
347  if (status != SUCCESS) return status;
348 
349  ksinv->selrfflip.rf = exc_ssfse90new;
350  ksinv->selrfflip.slthick = ksinv->params.slthick_exc;
351  ksinv->selrfflip.rf.flip = ksinv->params.flip_exc;
352  status = ks_eval_selrf(&ksinv->selrfflip, "ksinv_T2prep_flip");
353  if (status != SUCCESS) return status;
354 
355  if (ksinv->params.rftype == KSINV_RF_ADIABATIC) {
356  /*adiabatic refoc and inversion pulses */
357  if (cffield >= 30000){
358  ksinv->selrfinv.rf = adinv_sh3t2; /* KSFoundation_GERF.h */
359  } else {
360  ksinv->selrfinv.rf = adinv_shNvrg5b; /* KSFoundation_GERF.h */
361  }
362  } else {
363  ksinv->selrfinv.rf = ref_se1b4;
364  }
365 
366  if (ksinv->params.rftype_refoc == KSINV_RF_ADIABATIC) {
367  /*adiabatic refoc and inversion pulses */
368  if (cffield >= 30000){
369  ksinv->selrfrefoc.rf = adinv_sh3t2; /* KSFoundation_GERF.h */
370  } else {
371  ksinv->selrfrefoc.rf = adinv_shNvrg5b; /* KSFoundation_GERF.h */
372  }
373  } else {
374  ksinv->selrfrefoc.rf = ref_se1b4;
375  }
376 
377  ksinv->selrfrefoc.rf.role = KS_RF_ROLE_REF;
378  ksinv->selrfrefoc.rf.flip = ksinv->params.flip;
379  ksinv->selrfrefoc.slthick = ksinv->params.slthick;
380  status = ks_eval_selrf(&ksinv->selrfrefoc, "ksinv_T2prep_refoc");
381  if (status != SUCCESS) return status;
382 
383  ksinv->selrfinv.rf.role = KS_RF_ROLE_INV;
384  ksinv->selrfinv.rf.flip = ksinv->params.flip;
385  ksinv->selrfinv.slthick = ksinv->params.slthick;
386  status = ks_eval_selrf(&ksinv->selrfinv, "ksinv_T2prep_inv");
387  if (status != SUCCESS) return status;
388 
389  ksinv->selrfflip.pregrad = ksinv->selrfflip.postgrad;
390  /* ksinv->selrfexc.pregrad is empty --> no postgrad for selrfflip.postgrad*/
391  ksinv->selrfflip.postgrad = ksinv->selrfexc.pregrad;
392 
393  return SUCCESS;
394 
395 } /* ksinv_eval_setupt2prep() */
KS_SELRF selrfinv
Definition: KSInversion.e:102
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
Definition: KSFoundation.h:1953
Definition: KSFoundation.h:1953
DECL_TYPE KS_RF adinv_sh3t2
Definition: KSFoundation_GERF.c:125
float slthick_exc
Definition: KSInversion.e:89
Definition: KSInversion.e:46
float flip
Definition: KSFoundation.h:940
KS_TRAP pregrad
Definition: KSFoundation.h:1490
KS_SELRF selrfflip
Definition: KSInversion.e:105
KS_RF rf
Definition: KSFoundation.h:1485
int rftype_refoc
Definition: KSInversion.e:92
KS_SELRF selrfexc
Definition: KSInversion.e:104
DECL_TYPE KS_RF adinv_shNvrg5b
Definition: KSFoundation_GERF.c:122
KS_TRAP postgrad
Definition: KSFoundation.h:1492
float flip_exc
Definition: KSInversion.e:88
float slthick
Definition: KSInversion.e:78
DECL_TYPE KS_RF exc_ssfse90new
Definition: KSFoundation_GERF.c:71
DECL_TYPE KS_RF ref_se1b4
Definition: KSFoundation_GERF.c:104
KS_SELRF selrfrefoc
Definition: KSInversion.e:106
KSINV_PARAMS params
Definition: KSInversion.e:101
float flip
Definition: KSInversion.e:77
int rftype
Definition: KSInversion.e:80
float slthick
Definition: KSFoundation.h:1487

◆ ksinv_eval_setupobjects()

STATUS ksinv_eval_setupobjects ( KSINV_SEQUENCE ksinv,
const char *  suffix,
KS_SELRF custom_selrf 
)

Sets up the sequence objects for the inversion sequence module (KSINV_SEQUENCE ksinv)

KSInversion.e has two inversion sequence modules, ksinv1 and ksinv2, the latter only active for dual-IR. These are both declared in @ipgexport in KSInversion.e.

This function takes one of these sequence modules as first input argument (called from ksinv_eval()) and sets up the sequence objects in that KSINV_SEQUENCE, with suffix as the unique suffix name for the sequence module (currently "1" and "2" in ksinv_eval()).

Parameters
[in,out]ksinvPointer to a KSINV_SEQUENCE sequence module to be set up
[in]suffixSuffix string to att to "ksinv" for the description of the sequence module
[in,out]custom_selrfOptional pointer to KS_SELRF for custom inversion RF pulse. Pass NULL to use default RF pulses.
Return values
STATUSSUCCESS or FAILURE
414  {
415  STATUS status;
416  char tmpstr[1000];
417 
418  /* if irmode == KSINV_OFF, reset and return */
419  if (ksinv->params.irmode == KSINV_OFF) {
420  ksinv_init_sequence(ksinv);
421  return SUCCESS;
422  }
423 
424  if (ksinv->params.irmode == KSINV_FLAIR_T2PREP_BLOCK) {
425  /* t2prepped selective RF inversion */
426  status = ksinv_eval_setupt2prep(ksinv);
427  if (status != SUCCESS) return status;
428  } else {
429  /* Selective RF inversion */
430  status = ksinv_eval_setuprf(ksinv, suffix, custom_selrf);
431  if (status != SUCCESS) return status;
432  }
433 
434  /* set up spoiler */
435  ksinv->spoiler.area = ksinv->params.spoilerarea;
436  sprintf(tmpstr, "ksinv_spoiler%s", suffix);
437  /* make a trap that has 3x lower slewrate than normal, since minimum IR seq duration is not time critical */
439  /* status = ks_eval_trap(&ksinv->spoiler, tmpstr); */
440  if (status != SUCCESS) return status;
441 
442 
443  /* Name seqmodule and setup seqctrl with desired SSI time and zero duration. .min_duration will be set in ksinv_pg() */
444  ks_init_seqcontrol(&ksinv->seqctrl);
445  sprintf(tmpstr, "ksinv%s", suffix);
446  strcpy(ksinv->seqctrl.description, tmpstr);
447 
448  return SUCCESS;
449 
450 } /* ksinv_eval_setupobjects() */
float ks_syslimits_ampmax(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:201
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
int irmode
Definition: KSInversion.e:76
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
STATUS ksinv_eval_setupt2prep(KSINV_SEQUENCE *ksinv)
Definition: KSInversion.e:339
LOG_GRAD loggrd
STATUS ksinv_eval_setuprf(KSINV_SEQUENCE *ksinv, const char *suffix, KS_SELRF *custom_selrf)
Sets up the RF sequence object for the inversion sequence module (KSINV_SEQUENCE ksinv)
Definition: KSInversion.e:288
STATUS ks_eval_trap_constrained(KS_TRAP *trap, const char *const desc, float ampmax, float slewrate, int minduration) WARN_UNUSED_RESULT
Sets up a trapezoid using a KS_TRAP sequence object with gradient constraints specified as input argu...
Definition: KSFoundation_host.c:319
float spoilerarea
Definition: KSInversion.e:81
float area
Definition: KSFoundation.h:582
float ks_syslimits_slewrate(LOG_GRAD loggrd)
Returns the maximum slewrate that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:248
Definition: KSInversion.e:45
KSINV_PARAMS params
Definition: KSInversion.e:101
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
void ksinv_init_sequence(KSINV_SEQUENCE *ksinv)
Resets the KSINV_SEQUENCE struct (arg 1) to KSINV_INIT_SEQUENCE
Definition: KSInversion.e:216
Definition: KSInversion.e:45
KS_TRAP spoiler
Definition: KSInversion.e:103

◆ ksinv_eval_nullti()

int ksinv_eval_nullti ( int  TR,
int  T1value,
int  seqdur 
)

Calculates the TI value necessary to null the signal from a tissue with a given T1 value,

the TR of the sequence and the main sequence duration, all in [us]

Parameters
[in]TRRepetition time in [us]
[in]T1valueThe T1 value of the tissue to be nulled in [us]
[in]seqdurThe duration of the main sequence in [us]
Return values
TItimeInversion time in [us]
465  {
466 
467  return (int) ((double) T1value * ( log(2.0) - log(1.0 + exp(-((double) TR - (double) seqdur)/((double) T1value))) ));
468 
469 } /* ksinv_eval_nullti() */

◆ ksinv_eval_duration()

STATUS ksinv_eval_duration ( KSINV_SEQUENCE ksinv,
int  TI,
int  coreslice_momentstart 
)

Sets the sequence module duration of a KSINV_SEQUENCE module based on an inversion time (TI) and the delay time from the start of the main sequence to its excitation center

For simple main sequences consisting of only one sequence module each time it is played out (i.e. without additional fatsat or spatial sat sequences attached before each main sequence), coreslice_momentstart is typically a small value of a few [ms] indicating the isocenter of the excitation pulse of the main sequence measured from the start of the main sequence. When e.g. a fatsat pulse sequence module is added before each main sequence module, this needs to be taken into account to get the correct inversion time. In these cases coreslice_momentstart should be larger (to also include any leading extra sequence module between the inversion module and the main sequence module, and consequently the duration of the inversion module becomes proportionally smaller. If TI is short in relation to coreslice_momentstart this function will return an error.

Parameters
[in,out]ksinvPointer to a KSINV_SEQUENCE sequence module
[in]TIDesired inversion time in [us]
[in]coreslice_momentstartThe delay time from the end of the inversion module to the isocenter of the excitation pulse of the main sequence
Return values
TItimeInversion time in [us]
495  {
496 
497  if (ksinv->seqctrl.momentstart <= 0) {
498  return ks_error("%s: Moment start position of the inversion sequence (arg 1) must be > 0", __FUNCTION__);
499  }
500  if (TI <= 0) {
501  return ks_error("%s: TI must be > 0", __FUNCTION__);
502  }
503  if (coreslice_momentstart <= 0) {
504  return ks_error("%s: The core slice moment start position must be > 0", __FUNCTION__);
505  }
506  if (ksinv->params.irmode != KSINV_IR_SIMPLE) {
507  return ks_error("%s: ksinv.params.irmode must be KSINV_IR_SIMPLE for this function", __FUNCTION__);
508  }
509 
510  ksinv->params.nslicesahead = 0;
511  ksinv->params.nflairslices = 0;
512 
513  ksinv->seqctrl.duration = RUP_GRD(TI + ksinv->seqctrl.momentstart - coreslice_momentstart);
514 
515  if (ksinv->seqctrl.min_duration > ksinv->seqctrl.duration) {
516  return ks_error("%s: Input args resulted in a a too short inv. seq. duration", __FUNCTION__);
517  }
518 
519  return SUCCESS;
520 
521 } /* ksinv_eval_duration() */
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int momentstart
Definition: KSFoundation.h:1136
int duration
Definition: KSFoundation.h:1135
int nslicesahead
Definition: KSInversion.e:84
int irmode
Definition: KSInversion.e:76
int min_duration
Definition: KSFoundation.h:1132
int nflairslices
Definition: KSInversion.e:85
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45

◆ ksinv_eval_duration_t1value()

STATUS ksinv_eval_duration_t1value ( KSINV_SEQUENCE ksinv,
int *  TR,
int *  TI,
int  approxti_flag,
int  coreslice_momentstart,
int  coreslice_duration,
int  mainseq_mindur,
int  T1value_toNull,
int  slperpass 
)

Sets the sequence module duration of a KSINV_SEQUENCE as well as TI and TR (slice-ahead IR)

This function enables the slice-ahead inversion mode, where the duration of the sequence module is determined while iteratively finding TI and TR, based on the duration and momentstart of the core slice playout. One 'core slice' consists of the main sequence and all other sequence modules played out every time with the main sequence directly before or after, e.g. [FatSat]-[SpatialSat]-[Mainsequence].

Optionally, one can pass in an approxti_flag. If FALSE (= 0), then the inversion module duration is set to meet exactly the TI that will null a tissue with a T1-value of T1value_toNull. As with any IR module, the minimum duration (ksinv.seqctrl.min_duration) given by the RF pulse and spoiler is very short in comparison to the actual duration (ksinv.seqctrl.duration) since TI >> min_duration.

This function reduces the duration significantly by playing the IR module several slices ahead of the main sequence slice. This reduces the ksinv sequence module duration by one or more whole units of coreslice_duration, while still magnetically maintaining the inversion time (TI). The number of slices that the inversion module should be played out ahead of the main sequence is stored in ksinv.params.nslicesahead. Now, if approxti_flag = TRUE, the duration of this ksinv sequence module will be set to its minimum (ksinv.seqctrl.min_duration), and TI will be approximated to a whole number of coreslice_duration. This works best for long T1value_toNull and reasonably short coreslice_duration as the percent error in TI will be low. With approxti_flag = TRUE the scan time will be significantly reduced in general.

As this function estimates the optimal TR and TI iteratively, AutoTR and AutoTI modes must be used when calling this function. Typically T1-FLAIR uses slice-ahead IR, but STIR should also be more efficient compared to a simple IR approach. See also ksinv_eval_multislice().

Parameters
[in,out]ksinvPointer to KSINV_SEQUENCE sequence module to set up
[out]TRPointer to the repetition time (TR) resulting from the interative search in [us]
[out]TIPointer to the inversion time (TI) resulting from the interative search in [us]
[in]approxti_flag0: Make TI exact 1: Make TI approximate (shorter scan time in general)
[in]coreslice_momentstartTime between the end of the inversion module and the moment start of the main sequence.
[in]coreslice_durationDuration of the 'core slice' (main sequence + other attached sequence modules)
[in]mainseq_mindurMinimum duration of just the main sequence (used by ksinv_eval_nullti())
[in]T1value_toNullT1 value to null in [us]
[in]slperpassNumber of slices to play out in one pass (acquisition)
Return values
STATUSSUCCESS or FAILURE
567  {
568 
569  if (ksinv->seqctrl.momentstart <= 0) {
570  return ks_error("%s (%s): Moment start position of the inversion sequence (arg 1) must be > 0", __FUNCTION__, ksinv->seqctrl.description);
571  }
572  if (TR == NULL) {
573  return ks_error("%s (%s): TR pointer cannot be NULL", __FUNCTION__, ksinv->seqctrl.description);
574  }
575  if (TI == NULL) {
576  return ks_error("%s (%s): TI pointer cannot be NULL", __FUNCTION__, ksinv->seqctrl.description);
577  }
578  if (coreslice_momentstart <= 0) {
579  return ks_error("%s (%s): The core slice moment start position must be > 0", __FUNCTION__, ksinv->seqctrl.description);
580  }
581  if (coreslice_duration <= 0) {
582  /* core slice duration is the sequence time (incl. SSI time) for the main sequence and other sequence modules that
583  are played just before each main sequence (e.g. ChemSat, GRx Sat, Simple IR etc.) */
584  return ks_error("%s (%s): The core slice time (arg 4) [attached seq. modules+ main seq.] must be > 0", __FUNCTION__, ksinv->seqctrl.description);
585  }
586  if (slperpass < 1) {
587  return ks_error("%s (%s): slperpass must be > 0", __FUNCTION__, ksinv->seqctrl.description);
588  }
589  if (ksinv->params.irmode != KSINV_IR_SIMPLE && ksinv->params.irmode != KSINV_IR_SLICEAHEAD) {
590  return ks_error("%s (%s): ksinv.params.irmode must be either KSINV_IR_SIMPLE or KSINV_IR_SLICEAHEAD for this function", __FUNCTION__, ksinv->seqctrl.description);
591  }
592 
593  int i = 0;
594  int iter_max = 50;
595  int TItol = 20; /* TI error tolerance in [us] */
596  int tempTI;
597  int hasconverged = FALSE;
598  int reduce_sliceahead = 0;
599  int minimumTR_forslices = slperpass * (ksinv->seqctrl.min_duration + coreslice_duration);
600 
601  *TR = minimumTR_forslices;
602  *TI = ksinv_eval_nullti(*TR, T1value_toNull, mainseq_mindur);
603 
604  ksinv->seqctrl.duration = ksinv->seqctrl.min_duration;
605 
606  if (approxti_flag == TRUE) {
607  /* Optimal TI is approximated using discrete number of slice-aheads with ksinv->seqctrl.duration = ksinv->seqctrl.min_duration */
608 
609  /* set .duration = .min_duration (again to be safe) */
610  ksinv->seqctrl.duration = ksinv->seqctrl.min_duration;
611 
612  /* integer nslicesahead that comes closest to the desired TI */
613  ksinv->params.nslicesahead = (int) (((float) (*TI + ksinv->seqctrl.momentstart - ksinv->seqctrl.min_duration - coreslice_momentstart)) / ((float) (coreslice_duration + ksinv->seqctrl.min_duration)) + 0.5);
614 
615  /* adjust TI to reflect the approximation */
616  *TI = ksinv->params.nslicesahead * (coreslice_duration + ksinv->seqctrl.min_duration) - ksinv->seqctrl.momentstart + ksinv->seqctrl.min_duration + coreslice_momentstart;
617 
618  return SUCCESS;
619  }
620 
621 
622  while (hasconverged == FALSE && ksinv->params.nslicesahead >= 0) {
623 
624  while (hasconverged == FALSE && i++ < iter_max) {
625 
626  if (ksinv->params.irmode == KSINV_IR_SLICEAHEAD && slperpass > 1) {
627 
628  ksinv->params.nslicesahead = (*TI + ksinv->seqctrl.momentstart - ksinv->seqctrl.min_duration - coreslice_momentstart) / (coreslice_duration + ksinv->seqctrl.min_duration) - reduce_sliceahead;
629 
630  if (ksinv->params.nslicesahead < 0) {
631  ksinv->params.nslicesahead = 0;
632  } else if (ksinv->params.nslicesahead > (slperpass - 1)) {
633  ksinv->params.nslicesahead = slperpass - 1;
634  }
635  } else {
636  ksinv->params.nslicesahead = 0;
637  }
638 
639  /* duration of inversion module */
640  ksinv->seqctrl.duration = RUP_GRD((*TI + ksinv->seqctrl.momentstart - coreslice_momentstart - ksinv->params.nslicesahead * coreslice_duration) / (ksinv->params.nslicesahead + 1));
641 
642  /* prevent too small durations */
643  if (ksinv->seqctrl.min_duration > ksinv->seqctrl.duration) {
644  ksinv->seqctrl.duration = ksinv->seqctrl.min_duration;
645  }
646 
647  /* Update TR and TI after IR duration update */
648  *TR = slperpass * (ksinv->seqctrl.duration + coreslice_duration);
649  tempTI = ksinv_eval_nullti(*TR, T1value_toNull, mainseq_mindur);
650 
651  hasconverged = abs(tempTI - *TI) < TItol;
652 
653  *TI = tempTI;
654 
655  } /* inner while */
656 
657  reduce_sliceahead++;
658  i = 0;
659 
660  } /* outer while */
661 
662 
663  /* watchdogs */
664  if (i >= iter_max) {
665  return ks_error("%s (%s): No solution. Increase ETL or #slices", __FUNCTION__, ksinv1.seqctrl.description);
666  }
667  if (*TI == 0) {
668  return ks_error("%s (%s): TI became zero", __FUNCTION__, ksinv->seqctrl.description);
669  }
670  if (*TR < minimumTR_forslices) {
671  return ks_error("%s (%s): TR became too short to fit the number of slices", __FUNCTION__, ksinv->seqctrl.description);
672  }
673  if (ksinv->seqctrl.min_duration > ksinv->seqctrl.duration) {
674  return ks_error("%s: Input args resulted in a a too short inv. seq. duration", __FUNCTION__);
675  }
676 
677  return SUCCESS;
678 
679 } /* ksinv_eval_duration_t1value() */
int ksinv_eval_nullti(int TR, int T1value, int seqdur)
Calculates the TI value necessary to null the signal from a tissue with a given T1 value...
Definition: KSInversion.e:465
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int32_t i
Definition: KSFoundation_tgt.c:1389
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
Definition: KSInversion.e:45
int momentstart
Definition: KSFoundation.h:1136
int duration
Definition: KSFoundation.h:1135
int nslicesahead
Definition: KSInversion.e:84
int irmode
Definition: KSInversion.e:76
int min_duration
Definition: KSFoundation.h:1132
KSINV_PARAMS params
Definition: KSInversion.e:101
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
Definition: KSInversion.e:45

◆ ksinv_eval_duration_flairblock()

STATUS ksinv_eval_duration_flairblock ( KSINV_SEQUENCE ksinv,
int  TI,
int  coreslice_momentstart,
int  coreslice_duration,
int  slperpass 
)

Sets the sequence module duration of a KSINV_SEQUENCE for a FLAIR block design

This function sets the duration for an KSINV_SEQUENCE module in a FLAIR block design, where ksinv.params.nflairslices number of inversion pulses are played first (at different slice locations) followed by equally many 'core slice' playouts (main sequence + optional other sequence modules attached to the main sequence).

The maximum number of FLAIR slices is capped by slperpass, which is the maximum number of slices to fit in one TR. As each inversion module must be as long as the coreslice_duration in a FLAIR block design, the integer number of flair slices (ksinv.params.nflairslices) rarely fit exactly in the desired TI time, why the duration of the inversion modules are increased to exactly fit this available time. This means that after calling this function, one must make sure that the duration of the main sequence is also increased accordingly. This is done in ksinv_eval_multislice().

Parameters
[in,out]ksinvPointer to KSINV_SEQUENCE sequence module to set up
[in]TIThe inversion time (TI) resulting from the interative search in [us]
[in]coreslice_momentstartTime between the end of closest inversion module and the moment start of the main sequence.
[in]coreslice_durationDuration of the coreslice (main sequence + other attached sequence modules)
[in]slperpassNumber of slices to play out in one pass (acquisition)
Return values
STATUSSUCCESS or FAILURE
709  {
710  int avail_flairseqtime;
711 
712  if (TI <= 0) {
713  return ks_error("%s: TI must be > 0", __FUNCTION__);
714  }
715  if (coreslice_momentstart <= 0) {
716  return ks_error("%s: The core slice moment start position must be > 0", __FUNCTION__);
717  }
718  if (coreslice_duration <= 0) {
719  /* core slice duration is the sequence time (incl. SSI time) for the main sequence and other sequence modules that
720  are played just before each main sequence (e.g. ChemSat, GRx Sat, Simple IR etc.) */
721  return ks_error("%s: The core slice time (arg 3) [attached seq. modules+ main seq.] must be > 0", __FUNCTION__);
722  }
723  if (ksinv->seqctrl.min_duration > coreslice_duration) {
724  return ks_error("%s: Minimum FLAIR slice duration must be less than the core slice time", __FUNCTION__);
725  }
726  if (TI < ksinv->seqctrl.min_duration - ksinv->seqctrl.momentstart + coreslice_momentstart) {
727  return ks_error("%s: TI too short to fit one inversion slice", __FUNCTION__);
728  }
729 
731  return ks_error("%s: ksinv.params.irmode must be KSINV_FLAIR_BLOCK or KSINV_FLAIR_T2PREP_BLOCK for this function", __FUNCTION__);
732  }
733  if (slperpass < 1) {
734  return ks_error("%s: #slices per pass (5th arg) must be at least 1", __FUNCTION__);
735  }
736 
737  ksinv->params.nslicesahead = 0;
738 
739  avail_flairseqtime = TI - coreslice_momentstart + ksinv->seqctrl.momentstart;
740 
741  /* how many slices that can be fitted within 'opti' */
742  ksinv->params.nflairslices = avail_flairseqtime / coreslice_duration;
743 
744  if (ksinv->params.nflairslices == 0) {
745  /* round-up (fall back to simple IR style). We have already checked that TI is long enough to fit one IR playout */
746  ksinv->params.nflairslices = 1;
747  }
748 
749  /* don't exceed the total number of slices per pass */
750  if (ksinv->params.nflairslices > slperpass) {
751  ksinv->params.nflairslices = slperpass;
752  }
753 
755 
756  /* increase the duration to fill up to 'avail_flairseqtime'
757  N.B: The calling function must also increase the duration of its main sequence to fill up corresponding 'avail_flairseqtime' in the core slice block */
758  ksinv->seqctrl.duration = RUP_GRD(avail_flairseqtime / ksinv->params.nflairslices);
759 
760  if (ksinv->seqctrl.duration < coreslice_duration && ksinv->params.nflairslices > 1) {
761  return ks_error("%s: FLAIR slice duration became shorter than coreslice duration", __FUNCTION__);
762  }
763 
764  return SUCCESS;
765 
766 } /* ksinv_eval_duration_flairblock() */
KS_SELRF selrfinv
Definition: KSInversion.e:102
KS_SMS_INFO sms_info
Definition: KSFoundation.h:1494
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
Definition: KSInversion.e:45
int momentstart
Definition: KSFoundation.h:1136
int duration
Definition: KSFoundation.h:1135
int nslicesahead
Definition: KSInversion.e:84
int irmode
Definition: KSInversion.e:76
int min_duration
Definition: KSFoundation.h:1132
int nflairslices
Definition: KSInversion.e:85
int mb_factor
Definition: KSFoundation.h:1368
Definition: KSInversion.e:45
KSINV_PARAMS params
Definition: KSInversion.e:101

◆ ksinv_eval_setfilltr()

STATUS ksinv_eval_setfilltr ( KS_SEQ_CONTROL filltr,
const char *const  desc,
int  duration 
)

Sets the duration of a wait sequence (filltr) between FLAIR-blocks to meet manual TR

In ksinv_eval_duration_flairblock(), ksinv.params.nflairslices number of inversion pulses are played out before equally many main sequence playouts. This time corresponds to: 2 * ksinv.params.nflairslices * coreslice_duration

If TR is set manually (AutoTR off), this filltr wait sequence module is set to fill up the time to the desired TR. When ksinv.params.nflairslices <= number of slices per pass, two or more FLAIR-blocks will be played out in ksinv_scan_sliceloop(), where each block will end with this wait sequence. Therefore, the duration of this wait sequence will be reduced in time if used more than once in each slice loop, to keep the same total wait duration given by: filltr duration = TR - N * (2 * ksinv.params.nflairslices * coreslice_duration, where N is an integer >= 1.

If the duration is zero, the description will be ignored and set to "fillTR_disabled".

Parameters
[in,out]filltrPointer to the KS_SEQ_CONTROL for the fillTR wait sequence
[in]descDescription of the wait sequence
[in]durationDuration of the wait sequence
Return values
STATUSSUCCESS or FAILURE
794  {
795 
796  strcpy(filltr->description, desc);
797 
798  if (duration > 0) {
799  strcpy(filltr->description, desc);
801  filltr->min_duration = RUP_GRD(ksinv_filltr.ssi_time);
802  filltr->duration = RUP_GRD(duration);
803 
804  if (filltr->duration < filltr->min_duration || filltr->duration < filltr->ssi_time) {
805  return ks_error("%s: filltr.duration must be >= .min_duration and .ssi_time", __FUNCTION__);
806  }
807 
808  } else {
809  ks_init_seqcontrol(filltr);
811  strcpy(filltr->description, "fillTR_disabled");
812  }
813 
814  return SUCCESS;
815 
816 } /* ksinv_eval_setfilltr() */
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int duration
Definition: KSFoundation.h:1135
int ksinv_filltr_ssi_time
Definition: KSInversion.e:158
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 min_duration
Definition: KSFoundation.h:1132
int ssi_time
Definition: KSFoundation.h:1134
KS_DESCRIPTION description
Definition: KSFoundation.h:1141
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128

◆ ksinv_init_UI()

STATUS ksinv_init_UI ( )

Initializes inversion related UI

Pre-DV26:

  • T2FLAIR set by: opflair == OPFLAIR_GROUP
  • T1FLAIR set by: opflair == OPFLAIR_INTERLEAVED

DV26+: UI buttons have been moved from column 2 (under FastSpinEcho/SSFSE) to column 3 (imaging options)

  • T2FLAIR set by: opt2flair == TRUE
  • T1FLAIR set by: opt1flair == TRUE

To be compatible with previous releases, this function sets the legacy opflair CV to the correct value, so that (for now) sequences using KSInversion.e can continue to use opflair despite the DV26 UI change.

Return values
STATUSSUCCESS or FAILURE
839  {
840 
841 #if EPIC_RELEASE >= 26
842 
843  set_incompatible(PSD_IOPT_T1FLAIR, PSD_IOPT_T2FLAIR);
844 
845  if (opt1flair == TRUE && opt2flair == TRUE) {
846  return ks_error("%s: Selection of T1FLAIR and T2FLAIR is not allowed", __FUNCTION__);
847  } else if (opt1flair == TRUE && opt2flair == FALSE) {
848  cvoverride(opflair, OPFLAIR_INTERLEAVED, PSD_FIX_ON, PSD_EXIST_ON);
849  } else if (opt2flair == TRUE && opt1flair == FALSE) {
850  cvoverride(opflair, OPFLAIR_GROUP, PSD_FIX_ON, PSD_EXIST_ON);
851  } else {
852  cvoverride(opflair, FALSE, PSD_FIX_ON, PSD_EXIST_ON);
853  }
854 
855 #endif
856 
857  return SUCCESS;
858 }
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT

◆ ksinv_eval_UI()

STATUS ksinv_eval_UI ( )

Gets the current UI and checks for valid inputs related to the inversion module(s)

The inversion mode(s) is initially dependent on the UI selections: T2-FLAIR, T1-FLAIR, IR-prep. Only 2D+Fast-SpinEcho enables the T2-FLAIR and T1-FLAIR buttons, but 2D+EchoPlanar enables a FLAIR-EPI button, which is the same thing as T2-FLAIR.

If the T2-FLAIR button is selected, opflair = OPFLAIR_GROUP, resulting in a FLAIR-block design (ksinv1.params.mode = KSINV_FLAIR_BLOCK).

If the T1-FLAIR button is selected, opflair = OPFLAIR_INTERLEAVED, resulting in a slice-ahead inversion mode (ksinv1.params.mode = KSINV_IR_SLICEAHEAD).

In T2-FLAIR and T1-FLAIR modes, only the first of the four UserCVs reserved by KSINV_EVAL() is shown.

For custom IR control, using simple IR or dual IR (in simple or sliceahead modes), opflair should be 0 and opirprep should be 1. For FSE (ksfse.e), this advanced mode is set by selecting FSE-IR. For EPI (ksepi.e), this mode is set by selecting SE-EPI, GE-EPI or DW-EPI and then selecting IRprep.

This function is used to set up inversion for 2D sequences and is not suited for future 3D psd support.

Return values
STATUSSUCCESS or FAILURE
886  {
887 
888 
889  cvmin(opti, 0);
890  cvmax(opti, 20s);
891  cvmax(optr, 240s); /* 4 mins */
892 
893 
894  if (oppseq != PSD_IR /* 3 */ && opirprep == FALSE && opflair == FALSE) {
895  /* no IR selection, disable everything IR related */
896  piuset &= ~(use_ir1_mode + use_ir1_t1 + use_ir2_mode + use_ir2_t1);
897  *ksinv1_mode = 0; _ksinv1_mode->existflag = TRUE; _ksinv1_mode->fixedflag = TRUE;
898  *ksinv2_mode = 0; _ksinv2_mode->existflag = TRUE; _ksinv2_mode->fixedflag = TRUE;
899  pitinub = 0;
900  return SUCCESS;
901  } else {
902  /* GE's ARC recon does not seem to like the combined use of
903  a) inversion
904  b) interleaved spacing (opileave)
905 
906  We can avoid this at the PSD selection stage by not allowing ARC
907  at all (disable_ioption) with any kind of inversion. This prevents however also ARC inversion
908  w/o interleaved spacing. A second level of defense is to allow ARC for inversion, but to check
909  whether interleaved spacing is on and if R > 1 (opaccel_ph_stride), but also checking if autolock
910  is off. If autolock is on, one assumes that the user wants to reconstruct the data from Pfiles,
911  which works without problems with ARC, inversion and interleaved spacing.
912  */
913 
914  if ((opileave == TRUE) && (oparc == TRUE) && (opaccel_ph_stride > 1.0) && (autolock == FALSE)) {
915  return ks_error("%s: Use ASSET for Inversion & Intleave Spacing", __FUNCTION__);
916  }
917 
918  }
919 
920 
921  if (opflair == OPFLAIR_GROUP || opflair == OPFLAIR_INTERLEAVED) {
922 
923  /* T2-FLAIR or T1-FLAIR */
924  if (cffield == 30000) {
925  _ksinv1_t1value->defval = T1_CSF_3T;
926  _ksinv2_t1value->defval = T1_WM_3T;
927  } else {
928  _ksinv1_t1value->defval = T1_CSF_1_5T;
929  _ksinv2_t1value->defval = T1_WM_1_5T;
930  }
931  } else {
932  /* maybe STIR */
933  if (cffield == 30000) {
934  _ksinv1_t1value->defval = T1_FAT_3T;
935  } else {
936  _ksinv1_t1value->defval = T1_FAT_1_5T;
937  }
938  _ksinv2_t1value->defval = 50; /* ms */
939  }
940 
941  /* presets for T1-FLAIR and T2-FLAIR */
942  if (opflair == OPFLAIR_GROUP) {
943  /* T2-FLAIR */
944  pitival2 = 3000ms;
945  pitival3 = 0; /* should never show */
946  pitival4 = 0;
947  pitival5 = 0;
948  pitival6 = 0;
949  if (_optr.defval < ksinv_mintr_t2flair) {
950  _optr.defval = ksinv_mintr_t2flair;
951  }
952  if (ksinv_t2prep == 1) {
954  } else {
956  }
957 
958  } else if (opflair == OPFLAIR_INTERLEAVED) {
959  /* T1-FLAIR (must use autoTI) */
960  pitival2 = 700ms;
961  pitival3 = 0; /* should never show */
962  pitival4 = 0;
963  pitival5 = 0;
964  pitival6 = 0;
966  } else {
967  pitival2 = 150ms;
968  pitival3 = 200ms;
969  pitival4 = 250ms;
970  pitival5 = 300ms;
971  pitival6 = 350ms;
972  _ksinv1_mode->defval = KSINV_IR_SIMPLE;
973  }
974 
975  /*** begin: opusers ***/
976 
977  /* [opuser] IR #1 mode */
978  _ksinv1_mode->minval = KSINV_OFF;
980  _cvdesc(_ksinv1_mode, "IR1 [0:Off 1:IR 2:SA-IR 3:FLAIR]");
981  if (_ksinv1_mode->existflag == FALSE) {
982  *ksinv1_mode = _ksinv1_mode->defval;
983  }
984 
985  /* [opuser] IR #2 mode */
986  _ksinv2_mode->minval = KSINV_OFF;
988  _ksinv2_mode->defval = KSINV_OFF;
989  _cvdesc(_ksinv2_mode, "IR2 [0:Off 1:IR 2:SA-IR]");
990  if (_ksinv2_mode->existflag == FALSE) {
991  *ksinv2_mode = _ksinv2_mode->defval;
992  }
993 
994  /* [opuser] IR #1. T1 value to NULL in [ms] (N.B.: not TI, but T1!) */
995  _ksinv1_t1value->minval = 0;
996  _ksinv1_t1value->maxval = 10000;
997  {
998  char tmpstr[100];
999  if (cffield == 30000) {
1000  sprintf(tmpstr, " IR1 - T1 to null [CSF:%d GM:%d WM:%d Fat:%d]", T1_CSF_3T, T1_GM_3T, T1_WM_3T, T1_FAT_3T);
1001  } else if (cffield == 15000) {
1002  sprintf(tmpstr, " IR1 - T1 to null [CSF:%d GM:%d WM:%d Fat:%d]", T1_CSF_1_5T, T1_GM_1_5T, T1_WM_1_5T, T1_FAT_1_5T);
1003  }
1004  _cvdesc(_ksinv1_t1value, tmpstr);
1005  }
1006  if (_ksinv1_t1value->existflag == FALSE) {
1007  *ksinv1_t1value = _ksinv1_t1value->defval;
1008  }
1009 
1010  /* [opuser] IR #2. T1 value to NULL in [ms] (N.B.: not TI, but T1!) */
1011  _ksinv2_t1value->minval = 0;
1012  _ksinv2_t1value->maxval = 10000;
1013  _cvdesc(_ksinv2_t1value, "IR2 - T1 to null");
1014  if (_ksinv2_t1value->existflag == FALSE) {
1015  *ksinv2_t1value = _ksinv2_t1value->defval;
1016  }
1017 
1018  /* turn on all these opuser CVs */
1020 
1021  if (((int) *ksinv1_mode) == KSINV_OFF) {
1022  /* if we are not doing inversion, hide the TI menu and other opusers and set opti = 0 */
1023  piuset &= ~(use_ir1_t1 + use_ir2_mode + use_ir2_t1);
1024  ksinv1_ti = 0;
1025  ksinv2_ti = 0;
1026  pitinub = 0;
1027  _ksinv1_mode->existflag = FALSE;
1028  _ksinv2_mode->existflag = FALSE;
1029  } else {
1030  /* Default: allow AutoTI and 5+1 rows in TI menu */
1031  piautoti = 1;
1032  pitinub = 6;
1033  }
1034 
1035  /* Set AutoTR and AutoTI */
1036  opautotr = TRUE;
1037  opautoti = TRUE;
1038 
1039  if (((int) *ksinv1_mode) == KSINV_IR_SLICEAHEAD) {
1040  pitrnub = 0; /* '2': only one menu choice (Minimum = AutoTR). '0': shown but greyed out (if also opautotr = 1) */
1041  pitinub = -1; /* '2': only one menu choice (AutoTI). '-1': shown but greyed out */
1042  }
1043 
1044  if (opflair == OPFLAIR_GROUP || opflair == OPFLAIR_INTERLEAVED) {
1045  /* T2-FLAIR or T1-FLAIR. Branded options, narrow options down */
1046 
1047  /* remove 0 mm gap from slice spacing menu */
1048  piisil = PSD_ON;
1049  float minspacing = exist(opslthick) / 2.0;
1050  piisnub = 5;
1051  piisval2 = minspacing;
1052  piisval3 = minspacing + 1;
1053  piisval4 = minspacing + 2;
1054  piisval5 = minspacing + 3;
1055  piisval6 = minspacing + 4;
1056 
1057  cvdef(opslspace, minspacing);
1058  opslspace = _opslspace.defval;
1059 
1060  if (opflair == OPFLAIR_INTERLEAVED) {
1061  pitrnub = 0;
1062  pitinub = -1;
1063  cvoverride(opautotr, PSD_ON, PSD_FIX_OFF, PSD_EXIST_ON);
1064  } else {
1065  pitrnub = 2; /* '2': only one menu choice (Minimum = AutoTR). '0': shown but greyed out (if also opautotr = 1) */
1066  pitinub = 2; /* '2': only one menu choice (AutoTI). '-1': shown but greyed out */
1067  }
1068 
1069  /* disable 2nd IR for T1/T2-FLAIR */
1070  _ksinv2_mode->existflag = FALSE;
1071  *ksinv2_mode = 0;
1072  ksinv2_ti = 0;
1073  piuset &= ~(use_ir1_mode + use_ir2_mode + use_ir2_t1);
1074  }
1075 
1076  /* if not AutoTI, set internal TI variable to selected TI (opti) and hide T1value opuser */
1077  if (opautoti == FALSE) {
1078  piuset &= ~use_ir1_t1;
1079  ksinv1_ti = exist(opti);
1080  }
1081 
1082  if (((int) *ksinv2_mode) == KSINV_OFF) {
1083  piuset &= ~use_ir2_t1;
1084  ksinv2_ti = 0;
1085  }
1086 
1087 
1088  return SUCCESS;
1089 
1090 } /* ksinv_eval_UI() */
int ksinv_mintr_t2flair
Definition: KSInversion.e:159
#define T1_CSF_3T
Definition: KSInversion.e:63
#define T1_WM_1_5T
Definition: KSInversion.e:68
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int use_ir1_mode
Definition: KSInversion.e:134
int use_ir2_t1
Definition: KSInversion.e:137
Definition: KSInversion.e:45
Definition: KSInversion.e:45
#define T1_FAT_3T
Definition: KSInversion.e:69
float * ksinv1_mode
Definition: KSInversion.e:140
int ksinv1_ti
Definition: KSInversion.e:131
int use_ir1_t1
Definition: KSInversion.e:135
int ksinv2_ti
Definition: KSInversion.e:132
int ksinv_t2prep
Definition: KSInversion.e:174
_cvfloat * _ksinv2_mode
Definition: KSInversion.e:145
_cvfloat * _ksinv1_t1value
Definition: KSInversion.e:146
int use_ir2_mode
Definition: KSInversion.e:136
_cvfloat * _ksinv2_t1value
Definition: KSInversion.e:147
_cvfloat * _ksinv1_mode
Definition: KSInversion.e:144
#define T1_WM_3T
Definition: KSInversion.e:67
#define T1_GM_1_5T
Definition: KSInversion.e:66
Definition: KSInversion.e:45
float * ksinv2_t1value
Definition: KSInversion.e:143
#define T1_FAT_1_5T
Definition: KSInversion.e:70
#define T1_GM_3T
Definition: KSInversion.e:65
float * ksinv1_t1value
Definition: KSInversion.e:142
#define T1_CSF_1_5T
Definition: KSInversion.e:64
Definition: KSInversion.e:45
float opslthick
Definition: KSInversion.e:45
float * ksinv2_mode
Definition: KSInversion.e:141
#define _cvdesc(cv, string)
Definition: KSFoundation.h:106

◆ ksinv_eval()

STATUS ksinv_eval ( KS_SEQ_COLLECTION seqcollection,
KS_SELRF custom_selrf 
)

Gets the IR-related UI parameters, creates sequence objects and min_duration for the inversion module(s), and adds these modules to KS_SEQ_COLLECTION.

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in,out]custom_selrfOptional pointer to KS_SELRF for custom inversion RF pulse. Pass NULL to use default RF pulses.
Return values
STATUSSUCCESS or FAILURE
1163  {
1164  STATUS status;
1165 
1166  ksinv_init_sequence(&ksinv1);/* 1st IR */
1167  ksinv_init_sequence(&ksinv2);/* 2nd IR */
1168  ks_init_seqcontrol(&ksinv_filltr); /* init fillTR for FLAIR-block */
1169 
1170  status = ksinv_eval_UI();
1171  if (status != SUCCESS) return status;
1172 
1173  if (((int) *ksinv1_mode) == KSINV_OFF) {
1174  /* If no IR1 flag on, return quietly */
1175  return SUCCESS;
1176  }
1177 
1178  /* Set inversion slice thickness. N.B.: 'avmaxacqs' = number of acqs shown in the UI (a.k.a. acqs = npasses) */
1179  if (existcv(opslthick) && (opslthick > 0)) {
1180  int intleavefact = IMax(2, 1, avmaxacqs);
1181  float slthickfact = intleavefact * (opslthick + opslspace) / opslthick;
1182 #if EPIC_RELEASE >= 26
1183  if (opt1flair == TRUE) {
1184  ksinv_slthickfact = (slthickfact <= KSINV_MAXTHICKFACT_T1FLAIR) ? slthickfact : KSINV_MAXTHICKFACT_T1FLAIR;
1185  } else {
1186  ksinv_slthickfact = (slthickfact <= KSINV_MAXTHICKFACT) ? slthickfact : KSINV_MAXTHICKFACT;
1187  }
1188 #else
1189  ksinv_slthickfact = (slthickfact <= KSINV_MAXTHICKFACT) ? slthickfact : KSINV_MAXTHICKFACT;
1190 #endif
1192  }
1193  if (existcv(optr) && existcv(opslquant) && existcv(opslspace) && opflair && (avmaxacqs <= 1) && (opssfse == FALSE) && (opslspace <= 0) && (opileave == 0)) {
1194  /* for single acquisition T1-FLAIR or T2-FLAIR, prevent too little spacing between slices it not interleaved
1195  spacing, but only once the user has set number of slices, TR, and slice gap (so we don't complain too early) */
1196  return ks_error("%s: Use slice gap or Intleave", __FUNCTION__);
1197  }
1198 
1199 
1200  /* single or 1st IR */
1202 
1203  status = ksinv_eval_setupobjects(&ksinv1, "1", custom_selrf);
1204  if (status != SUCCESS) return status;
1205 
1206  status = ksinv_pg(&ksinv1);
1207  if (status != SUCCESS) return status;
1208 
1210  if (status != SUCCESS) return status;
1211 
1212  /* FillTR sequence for KSINV_FLAIR_BLOCK. This is added after all slices have been played out each TR instead
1213  of increasing the duration of the main pulse sequence to fullfill TR */
1214  status = ksinv_eval_setfilltr(&ksinv_filltr, "fillTR", 0); /* initialize to zero */
1215  if (status != SUCCESS) return status;
1216 
1217 
1218  if (((int) *ksinv2_mode) != KSINV_OFF) {
1219 
1221 
1222  status = ksinv_eval_setupobjects(&ksinv2, "2", custom_selrf);
1223  if (status != SUCCESS) return status;
1224 
1225  status = ksinv_pg(&ksinv2);
1226  if (status != SUCCESS) return status;
1227 
1229  if (status != SUCCESS) return status;
1230 
1231  }
1232 
1233  return status;
1234 
1235 } /* ksinv_eval() */
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
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
int ksinv_pg(KSINV_SEQUENCE *)
Generation of the waveforms for the sequence objects in a KSINV_SEQUENCE
Definition: KSInversion.e:1937
float * ksinv1_mode
Definition: KSInversion.e:140
STATUS ksinv_eval_UI()
Gets the current UI and checks for valid inputs related to the inversion module(s)
Definition: KSInversion.e:886
float ksinv_slthickfact
Definition: KSInversion.e:167
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
STATUS ksinv_eval_setupobjects(KSINV_SEQUENCE *ksinv, const char *suffix, KS_SELRF *custom_selrf)
Sets up the sequence objects for the inversion sequence module (KSINV_SEQUENCE ksinv)
Definition: KSInversion.e:414
float ksinv_slthickfact_exc
Definition: KSInversion.e:179
void ksinv_eval_copycvs(KSINV_PARAMS *params, int mode)
Copy CVs into a common params struct (KSINV_PARAMS) used to steer this sequence module
Definition: KSInversion.e:234
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KSINV_PARAMS params
Definition: KSInversion.e:101
#define KSINV_MAXTHICKFACT
Definition: KSInversion.e:59
void ksinv_init_sequence(KSINV_SEQUENCE *ksinv)
Resets the KSINV_SEQUENCE struct (arg 1) to KSINV_INIT_SEQUENCE
Definition: KSInversion.e:216
Definition: KSInversion.e:45
float opslthick
float * ksinv2_mode
Definition: KSInversion.e:141
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
STATUS ksinv_eval_setfilltr(KS_SEQ_CONTROL *filltr, const char *const desc, int duration)
Sets the duration of a wait sequence (filltr) between FLAIR-blocks to meet manual TR...
Definition: KSInversion.e:794
#define KSINV_MAXTHICKFACT_T1FLAIR
Definition: KSInversion.e:60

◆ ksinv_eval_mintr()

int ksinv_eval_mintr ( const KS_SLICE_PLAN slice_plan,
KS_SEQ_COLLECTION seqcollection,
float  gheatfact,
KSINV_SEQUENCE ksinv1,
KSINV_SEQUENCE ksinv2,
KS_SEQ_CONTROL ksinv_filltr,
int(*)(const SCAN_INFO *, int, int, void **)  play_coreslice,
int  core_nargs,
void **  core_args 
)

Calculates the minimum TR allowed for the ksinv_scan_sliceloop()

Given the current durations of the sequence modules involved in the ksinv_scan_sliceloop(), this function calculates the minimum TR, accounting also for SAR and hardware limits.

This function expects a pointer to a scan function playing out one coreslice. The coreslice should play out the main sequence once (i.e. one slice), but the coreslice function may also play optional other sequence modules that should always be played together with the main sequence (e.g. fatsat).

As the number of arguments to the sequence's coreslice is psd-dependent, the function pointer play_coreslice must be a wrapper function to the coreslice function taking standardized input arguments (int) core_nargs and (void **) core_args. This coreslice wrapper function must be on the form: int coreslice_nargs(SCAN_INFO *, int storeslice, int core_nargs, void **core_args); If the coreslice function does not need any additional input arguments, core_nargs = 0, and core_args = NULL.

With this function pointer, ksinv_scan_sliceloop() can replace the sequence (non-inversion) sliceloop function, and play out the inversion module(s) and the sequence module(s) in the coreslice function.

After resetting the seqctrl.nseqinstances for all sequence modules in the sequence collection, ksinv_scan_sliceloop() is called once to increment seqctrl.nseqinstances by 1 for every time each sequence modules is played out. With this updated information, seqcollection is passed to ks_eval_gradrflimits(), which will calculate the total duration and add additional time for SAR/hardware limits. This time is the return value of ksinv_eval_mintr().

Parameters
[in]slice_planPointer to the KS_SLICE_PLAN struct holding the slice order information
[in]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]gheatfactValue in range [0,1] denoting how much the gradient heating limits should be honored (0:none, 1:full)
[in]ksinv1Pointer to KSINV_SEQUENCE corresponding to the 1st (or only) inversion. Cannot be NULL
[in]ksinv2Pointer to KSINV_SEQUENCE corresponding to an optional 2nd inversion. May be NULL
[in]ksinv_filltrPointer to KS_SEQ_CONTROL for fillTR sequence for FLAIR block modes. May be NULL
[in]play_coresliceFunction pointer to (the wrapper function to) the coreslice function of the sequence
[in]core_nargsNumber of extra input arguments to the coreslice wrapper function.
[in]core_argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's coreslice function
Return values
minTRMinimum TR for ksinv_scan_sliceloop() honoring SAR and hardware limits
1280  {
1281 
1282  /* must be run before each call to function pointer `play_coreslice()` to set all `seqctrl.nseqinstances` to 0 */
1284 
1285  ksinv_scan_sliceloop(slice_plan, ks_scan_info, 0, ksinv1, ksinv2, ksinv_filltr, KSINV_LOOP_NORMAL, play_coreslice, core_nargs, core_args); /* get sequence instance counts */
1286 
1287  return ks_eval_gradrflimits(NULL, seqcollection, gheatfact); /* minTR within limits given the number of sequence instances, durations and RF/grad content */
1288 
1289 } /* ksinv_eval_mintr() */
int ks_eval_gradrflimits(KS_SAR *sar, KS_SEQ_COLLECTION *seqcollection, float gheatfact)
Returns the time required to play out a certain number of sequence modules over some interval...
Definition: KSFoundation_host.c:4370
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
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
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
Definition: KSInversion.e:47
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
void ks_eval_seqcollection_resetninst(KS_SEQ_COLLECTION *seqcollection)
Set the .nseqinstances field of each sequence module (KS_SEQ_CONTROL) equal to 0
Definition: KSFoundation_host.c:4590
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksinv_eval_maxslicespertr()

int ksinv_eval_maxslicespertr ( int  TR,
KS_SLICE_PLAN  temp_slice_plan,
KS_SEQ_COLLECTION seqcollection,
float  gheatfact,
KSINV_SEQUENCE ksinv1,
KSINV_SEQUENCE ksinv2,
KS_SEQ_CONTROL ksinv_filltr,
int(*)(const SCAN_INFO *, int, int, void **)  play_coreslice,
int  core_nargs,
void **  core_args 
)

Calculates the maximum slices per TR using ksinv_scan_sliceloop()

Parameters
[in]TRRepetition time in [us]
[in]temp_slice_planPointer to the KS_SLICE_PLAN struct holding the slice order information
[in]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]gheatfactValue in range [0,1] denoting how much the gradient heating limits should be honored (0:none, 1:full)
[in]ksinv1Pointer to KSINV_SEQUENCE corresponding to the 1st (or only) inversion. Cannot be NULL
[in]ksinv2Pointer to KSINV_SEQUENCE corresponding to an optional 2nd inversion. May be NULL
[in]ksinv_filltrPointer to KS_SEQ_CONTROL for fillTR sequence for FLAIR block modes. May be NULL
[in]play_coresliceFunction pointer to (the wrapper function to) the coreslice function of the sequence
[in]core_nargsNumber of extra input arguments to the coreslice wrapper function.
[in]core_argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's coreslice function
Return values
MaxSlicesPerTRMaximum slices that can fit in the specified TR, honoring SAR and hardware limits
1313  {
1314  int max_slquant1 = 0;
1315  int i, invslicelooptime;
1316  for (i = 1; i < 1024; i++) {
1317 
1318  temp_slice_plan.nslices_per_pass = i; /* hack the slice plan with 'i' #slices to see when invslicelooptime becomes larger than TR */
1319 
1320  invslicelooptime = ksinv_eval_mintr(&temp_slice_plan, seqcollection, gheatfact, ksinv1, ksinv2, ksinv_filltr, play_coreslice, core_nargs, core_args);
1321 
1322  if (invslicelooptime == KS_NOTSET) {
1323  return KS_NOTSET;
1324  }
1325  if (invslicelooptime > TR) {
1326  return max_slquant1;
1327  }
1328  max_slquant1 = i;
1329  }
1330 
1331  return max_slquant1;
1332 
1333 } /* ksinv_eval_maxslicespertr() */
#define KS_NOTSET
Definition: KSFoundation.h:103
int32_t i
Definition: KSFoundation_tgt.c:1389
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
int nslices_per_pass
Definition: KSFoundation.h:1353
int ksinv_eval_mintr(const KS_SLICE_PLAN *slice_plan, KS_SEQ_COLLECTION *seqcollection, float gheatfact, KSINV_SEQUENCE *ksinv1, KSINV_SEQUENCE *ksinv2, KS_SEQ_CONTROL *ksinv_filltr, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
Calculates the minimum TR allowed for the ksinv_scan_sliceloop()
Definition: KSInversion.e:1279
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128

◆ ksinv_eval_flairblock()

STATUS ksinv_eval_flairblock ( KSINV_SEQUENCE ksinv,
int *  filltr_time,
int *  repetition_time,
int *  inversion_time,
int  autotr_flag,
int  T1tonull,
int  coreslice_momentstart,
int  coreslice_duration,
int  slperpass 
)

FLAIR block calculations

Parameters
[in,out]ksinvPointer to KSINV_SEQUENCE. ksinv.params.irmode must be KSINV_FLAIR_BLOCK and ksinv.seqctrl.min_duration and ksinv.seqctrl.momentstart both > 0.
[out]filltr_timeThe time that needs to be added after all slices played out to fill up to the manual TR
[in,out]repetition_timePointer to the repetition time [us]. If autotr_flag = TRUE, this value will be set and returned as TR to the calling function. If autotr_flag = FALSE, 'repetition_time' will be used as TR here
[in,out]inversion_timePointer to the inversion time [us]. If 'T1tonull' > 0, this value will be set and returned as TI to the calling function. If 'T1tonull' = 0, 'inversion_time' will be used as TI here
[in]autotr_flagTRUE/FALSE flag for autoTR. If TRUE, 'repetition_time' will be updated
[in]T1tonullT1-value to null. 0: Off (value of 'inversion_time' is used. >0: Use this T1-value to calculate the TI value and update and return 'inversion_time'
[in]coreslice_momentstartTime between the end of closest inversion module and the moment start of the main sequence.
[in]coreslice_durationDuration of the coreslice (main sequence + other attached sequence modules)
[in]slperpassNumber of slices to play out in one pass (acquisition)
Return values
STATUSSUCCESS or FAILURE
1354  {
1355  int i = 0;
1356  int iter_max = 20;
1357  int TRtol = 20; /* TR error tolerance in [us] */
1358  int hasconverged = FALSE;
1359  int cap_nflairslices = FALSE;
1360  int lowest_nflairslices = slperpass;
1361  int minTR, TR, TI;
1362  int nflairblocks;
1363  int lastTR = 0;
1364  int flair_duration;
1365  int timetoadd_perTR;
1366  STATUS status;
1367 
1368  if (filltr_time == NULL || repetition_time == NULL || inversion_time == NULL) {
1369  return ks_error("%s: 2nd-4th args must be non-NULL int pointers", __FUNCTION__);
1370  }
1371  if (autotr_flag != 0 && autotr_flag != 1) {
1372  return ks_error("%s: autotr flag must be 0 (false) or 1 (true)", __FUNCTION__);
1373  }
1374 
1375  if (autotr_flag) {
1376  /* AutoTR */
1377  TR = 20s; /* starting guess */
1378  } else {
1379  TR = *repetition_time;
1380  }
1381 
1382 
1383  do {
1384 
1385  if (T1tonull > 0) {
1386  /* AutoTI: set TI based on T1tonull and current TR (AutoTR) or fixed TR */
1387  TI = ksinv_eval_nullti(TR, T1tonull, coreslice_duration);
1388  } else {
1389  TI = *inversion_time;
1390  }
1391 
1392  /* duration of each inversion module in the FLAIR block. This function sets the field ksinv.params.nflairslices */
1393  status = ksinv_eval_duration_flairblock(ksinv, TI, coreslice_momentstart, coreslice_duration, (cap_nflairslices == TRUE) ? lowest_nflairslices : slperpass);
1394  if (status != SUCCESS) return status;
1395 
1396  /* minimum TR (ignoring grad/RF heating and SAR) */
1397  nflairblocks = CEIL_DIV(slperpass, ksinv->params.nflairslices); /* number of FLAIR blocks */
1398 
1399  flair_duration = (nflairblocks * ksinv->params.nflairslices + slperpass) * ksinv->seqctrl.duration;
1400 
1401  /* keep minTR above ksinv_mintr_t2flair */
1402  minTR = IMax(2, flair_duration, ksinv_mintr_t2flair);
1403 
1404  if (autotr_flag == TRUE) {
1405  TR = minTR;
1406  }
1407 
1408  /* wait sequence after each set (group) of FLAIR + core slices to fill up TR. C.f. ksinv_scan_sliceloop() */
1409  timetoadd_perTR = IMax(2, TR, ksinv_mintr_t2flair) - flair_duration;
1410  *filltr_time = RUP_GRD(timetoadd_perTR / nflairblocks);
1411 
1412  if (autotr_flag == TRUE) {
1413 
1414  /* converge check and lastTR update */
1415  hasconverged = abs(lastTR - minTR) < TRtol;
1416  lastTR = minTR;
1417 
1418  if (ksinv->params.nflairslices < lowest_nflairslices && cap_nflairslices == FALSE) {
1419  /* In the event that the number of FLAIR slices toggles between two (or more) values, this iteration process may not converge.
1420  We monitor the lowest nflairslices that occur during the first iteration round (lowest_nflairslices). If we reach iter_max, use lowest_nflairslices
1421  instead of slperass as last arg to ksinv_eval_duration_flairblock() to force nflairslices to this value, and re-iterate.
1422  If still no convergence, lowest_nflairslices is reduced by 1 */
1423  lowest_nflairslices = ksinv->params.nflairslices;
1424  }
1425  if (++i == iter_max) {
1426  /* Things to do when we have reached #iterations */
1427  if (lowest_nflairslices > 1) {
1428  i = 0; /* reset iteration counter */
1429  if (cap_nflairslices == FALSE) {
1430  /* try iterating a second time, now with the lowest number of nflairslices used in the iterations (lowest_nflairslices) */
1431  cap_nflairslices = TRUE;
1432  } else {
1433  /* try iterating again after the second time, now with lowest_nflairslices reduced by 1 */
1434  lowest_nflairslices--;
1435  }
1436  } else {
1437  return ks_error("%s: FLAIR-block - Combination of TI & TR not found after %d iterations", __FUNCTION__, iter_max);
1438  }
1439  }
1440 
1441  } /* autotr_flag */
1442 
1443  } while ((autotr_flag == TRUE) && (hasconverged == FALSE)); /* only iterate for AutoTR */
1444 
1445 
1446  if (TR < ksinv_mintr_t2flair) {
1447  return ks_error("%s: TR must be increased to %d ms", __FUNCTION__, CEIL_DIV(ksinv_mintr_t2flair, 1000));
1448  }
1449 
1450  *inversion_time = TI;
1451  *repetition_time = TR;
1452 
1453  return SUCCESS;
1454 
1455 }
int ksinv_eval_nullti(int TR, int T1value, int seqdur)
Calculates the TI value necessary to null the signal from a tissue with a given T1 value...
Definition: KSInversion.e:465
int ksinv_mintr_t2flair
Definition: KSInversion.e:159
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int32_t i
Definition: KSFoundation_tgt.c:1389
int duration
Definition: KSFoundation.h:1135
STATUS ksinv_eval_duration_flairblock(KSINV_SEQUENCE *ksinv, int TI, int coreslice_momentstart, int coreslice_duration, int slperpass)
Sets the sequence module duration of a KSINV_SEQUENCE for a FLAIR block design
Definition: KSInversion.e:709
int nflairslices
Definition: KSInversion.e:85
KSINV_PARAMS params
Definition: KSInversion.e:101

◆ ksinv_eval_flairblock_withmainupdate()

STATUS ksinv_eval_flairblock_withmainupdate ( KSINV_SEQUENCE ksinv,
KS_SEQ_CONTROL ksinv_filltr,
KS_SEQ_CONTROL mainseqctrl,
int *  repetition_time,
int *  inversion_time,
int  autotr_flag,
int  T1tonull,
int  coreslice_momentstart,
int  coreslice_duration,
int  slperpass 
)
1459  {
1460  STATUS status;
1461  int filltr_duration;
1462 
1463  status = ksinv_eval_flairblock(ksinv, &filltr_duration, repetition_time, inversion_time, autotr_flag, T1tonull, coreslice_momentstart, coreslice_duration, slperpass);
1464  if (status != SUCCESS) return status;
1465 
1466  /* set up fill TR sequence (to be played out CEIL_DIV(slperpass, ksinv->params.nflairslices) times per TR) unless filltr_duration < ssi_time */
1467  status = ksinv_eval_setfilltr(ksinv_filltr, "fillTR", (filltr_duration > ksinv_filltr_ssi_time) * filltr_duration);
1468  if (status != SUCCESS) return status;
1469 
1470  /* We must have the same seq duration for ksinv->seqctrl.duration and the coreslice duration, add round-up time due to nflairslices divisibility to the duration of the main sequence. */
1471  if (ksinv->seqctrl.duration > coreslice_duration) {
1472  mainseqctrl->duration += RUP_GRD(ksinv->seqctrl.duration - coreslice_duration);
1473  }
1474 
1475  return SUCCESS;
1476 
1477 }
STATUS ksinv_eval_flairblock(KSINV_SEQUENCE *ksinv, int *filltr_time, int *repetition_time, int *inversion_time, int autotr_flag, int T1tonull, int coreslice_momentstart, int coreslice_duration, int slperpass)
FLAIR block calculations
Definition: KSInversion.e:1354
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
int duration
Definition: KSFoundation.h:1135
int ksinv_filltr_ssi_time
Definition: KSInversion.e:158
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
STATUS ksinv_eval_setfilltr(KS_SEQ_CONTROL *filltr, const char *const desc, int duration)
Sets the duration of a wait sequence (filltr) between FLAIR-blocks to meet manual TR...
Definition: KSInversion.e:794

◆ ksinv_eval_multislice()

STATUS ksinv_eval_multislice ( KS_SEQ_COLLECTION seqcollection,
KS_SLICE_PLAN slice_plan,
int(*)(const SCAN_INFO *, int, int, void **)  play_coreslice,
int  core_nargs,
void **  core_args,
KS_SEQ_CONTROL mainseqctrl 
)

Calculates the duration of inversion module(s) for various inversion modes

This function is to be used by a 2D psd to set the inversion duration(s) for ksinv1 and possibly ksinv2 (dual IR). Before calling this function, the ksinv->params.irmode (and ksinv2.params.irmode) must be set to steer which type of inversion that should be performed. Here follows the inversion modes supported by this function:

Single inversion (ksinv2.params.irmode = KSINV_OFF):

  1. ksinv1.params.irmode = KSINV_FLAIR_BLOCK:
    • Heat handling: None, but will be caught in final SAR check at the end. Unlikely to happen for T2-FLAIR
  2. ksinv1.params.irmode = KSINV_IR_SIMPLE and manual TR (opautotr = FALSE):
    • Heat handling: Increase mainseqctrl->duration based on timetoadd_perTR
  3. ksinv1.params.irmode = KSINV_IR_SLICEAHEAD or ksinv1.params.irmode = KSINV_IR_SIMPLE and (opautotr = TRUE)
    • Heat handling: C.f. "Early grad/RF heat calculations" that increases mainseqctrl->duration before IR/TR timing calculations

Dual inversion:

  1. ksinv1.params.irmode = KSINV_IR_SIMPLE and ksinv2.params.irmode = KSINV_IR_SIMPLE
  2. ksinv1.params.irmode = KSINV_IR_SLICEAHEAD and ksinv2.params.irmode = KSINV_IR_SIMPLE
  3. ksinv1.params.irmode = KSINV_FLAIR_BLOCK and ksinv2.params.irmode = KSINV_IR_SIMPLE
  4. ksinv1.params.irmode = KSINV_IR_SLICEAHEAD and ksinv2.params.irmode = KSINV_IR_SLICEAHEAD. TI1 (opti) will be approximated
Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
[in]slice_planPointer to the KS_SLICE_PLAN struct holding the slice order information
[in]play_coresliceFunction pointer to (the wrapper function to) the coreslice function of the sequence
[in]core_nargsNumber of extra input arguments to the coreslice wrapper function.
[in]core_argsVoid pointer array pointing to the variables containing the actual values needed for the sequence's coreslice function
[in]mainseqctrlPointer to the KS_SEQ_CONTROL struct for the main sequence
Return values
MaxSlicesPerTRMaximum slices that can fit in the specified TR, honoring SAR and hardware limits
1516  {
1517 
1518  STATUS status;
1519  int coreslice_momentstart;
1520  int coreslice_duration;
1521  int minTR = 0;
1522  int timetoadd_perTR;
1523  SCAN_INFO dummy_slice_pos = DEFAULT_AXIAL_SCAN_INFO; /* dummy slice info for coreslice */
1524 
1525 
1526  /* return early if we don't have at least one inversion */
1527  if (ksinv1.params.irmode == KSINV_OFF) {
1528  return SUCCESS;
1529  }
1530 
1531  /* return early if #slices/TR = 0 */
1532  if (slice_plan->nslices_per_pass == 0) {
1533  return SUCCESS;
1534  }
1535 
1536 
1538  return ks_error("%s: DualIR: If 2nd IR is on, so must the 1st IR", __FUNCTION__);
1540  return ks_error("%s: DualIR: If 2nd IR is sliceahead, so must the 1st IR", __FUNCTION__);
1542  return ks_error("%s: DualIR: 2nd IR cannot be a FLAIR block", __FUNCTION__);
1543  }
1544 
1546  return ks_error("%s: 1st IR (ksinv1): approximate TI only applicable to sliceahead IR mode", __FUNCTION__);
1547  }
1549  return ks_error("%s: 2nd IR (ksinv2): approximate TI only applicable to sliceahead IR mode", __FUNCTION__);
1550  }
1551 
1552  /* ks_eval_seqcollection_durations_atleastminimum() makes sure seqctrl.duration is at least seqctrl.min_duration for all sequence modules */
1554  if (status != SUCCESS) return status;
1555 
1556 
1557  if ( (ksinv1.params.irmode == KSINV_IR_SLICEAHEAD) || ((ksinv1.params.irmode == KSINV_IR_SIMPLE) && (opautoti == TRUE) && (opautotr == TRUE)) ) {
1558 
1559  /*******************************************************************************************************
1560  * Early grad/RF heat calculations
1561  *******************************************************************************************************/
1562 
1563  /* For KSINV_IR_SLICEAHEAD mode, we need to check for grad/RF heating *first* in a worst case scenario where all sequence
1564  modules have .duration = .min_duration. The penalty time is added the main sequence duration to be within the limits.
1565  After this, we can start calculating the IR time(s). This is due to that the KSINV_IR_SLICEAHEAD mode in part uses inversion
1566  pulses from the previous TR to invert slices in the current TR, why the TR cannot be changed (increased) after these
1567  calculations due to later heating issues. The same applies to simple IR mode with both AutoTR and AutoTI.
1568  For these two cases, both TR and TI are consequences of the chosen T1 null value */
1569 
1570  /* at this point, the IR module(s), main sequence, and other sequence modules should have .duration = .min_duration. Check worst case (minimum duration modules) */
1571  minTR = ksinv_eval_mintr(slice_plan, seqcollection, ks_gheatfact, &ksinv1, &ksinv2, NULL, play_coreslice, core_nargs, core_args);
1572  if (minTR == KS_NOTSET) return FAILURE;
1573 
1574 
1575  /* how much TR needs to increase if we have only minimum duration modules */
1576  timetoadd_perTR = minTR - ksinv_scan_sliceloop(slice_plan, ks_scan_info, 0, &ksinv1, &ksinv2, NULL, KSINV_LOOP_NORMAL, play_coreslice, core_nargs, core_args);
1577 
1578  /* we spread the available timetoadd_perTR evenly, by increasing .duration of each slice by timetoadd_perTR/slice_plan->nslices_per_pass */
1579  mainseqctrl->duration += RUP_GRD(CEIL_DIV(timetoadd_perTR, slice_plan->nslices_per_pass));
1580 
1581  }
1582 
1583  /* get coreslice time, i.e. time for one slice. Note that this must come after early grad/RF heat calculation to reflect the increased mainseq duration */
1584  coreslice_duration = play_coreslice(&dummy_slice_pos, 0, core_nargs, core_args);
1585 
1586  /* momentstart will be = mainseqctrl->momentstart if there is no other sequence module in play_coreslice(). However if the coreslice function contains
1587  other sequence module they are required to be placed before the main sequence module to assure the inversion time is correctly calculated */
1588  coreslice_momentstart = coreslice_duration - mainseqctrl->duration + mainseqctrl->momentstart;
1589 
1590 
1591 
1593 
1594  /*******************************************************************************************************
1595  * First and second IR when both are in mode KSINV_IR_SLICEAHEAD
1596  *******************************************************************************************************/
1597 
1598  /* mainseqctrl->duration already prolonged to meed grad/RF limits if necessary (see above).
1599  If both inversion pulses modes are KSINV_IR_SLICEAHEAD, the first IR has to get an approximate TI time using an
1600  (integer) ksinv1.params.nslicesahead and ksinv1.seqctrl.duration = ksinv1.seqctrl.min_duration. When calculating
1601  the sequence duration for ksinv2, we need to reserve this minimum time (ksinv1.seqctrl.min_duration) between the
1602  main sequence and ksinv2. Both IR pulses in KSINV_IR_SLICEAHEAD mode is faster, but the TI time for the first one
1603  will not be exact. For an FSE train of 200 ms, the TI will be rounded off by 200/2 ms at most, but since the 1st
1604  TI is usually 2500 ms when two IRs are used it may be ok */
1605 
1606  if (opautotr == FALSE || opautoti == FALSE) {
1607  return ks_error("%s: sliceahead mode requires AutoTI and AutoTR", __FUNCTION__);
1608  }
1609 
1610  /* 1st IR duration fixed to minimum */
1612 
1613  /* 2nd IR: get sequence module duration, TR and TI based on T1 null value and coreslice duration (iterative). Approximate TI if ksinv2.approxti = TRUE */
1614  status = ksinv_eval_duration_t1value(&ksinv2, &minTR, &ksinv2_ti, ksinv2.params.approxti, coreslice_momentstart, coreslice_duration + ksinv1.seqctrl.duration, mainseqctrl->min_duration, (int) (*ksinv2_t1value * 1000.0) /* [ms]->[us] */, slice_plan->nslices_per_pass);
1615  if (status != SUCCESS) return status;
1616 
1617  /* 1st IR (TI based on T1 to null) */
1618  ksinv1_ti = ksinv_eval_nullti(minTR, (int) (*ksinv1_t1value * 1000.0) /* [ms]->[us] */, mainseqctrl->min_duration);
1619 
1620  /* 1st IR (always approximate TI, using .duration = .min_duration) */
1621  ksinv1.params.nslicesahead = (ksinv1_ti + ksinv1.seqctrl.momentstart - coreslice_momentstart - ksinv1.seqctrl.min_duration) / (coreslice_duration + ksinv1.seqctrl.min_duration);
1622  ksinv1_ti = ksinv1.params.nslicesahead * (coreslice_duration + ksinv1.seqctrl.min_duration) - ksinv1.seqctrl.momentstart + coreslice_momentstart;
1623 
1624 
1625  } else if (ksinv2.params.irmode == KSINV_IR_SIMPLE) {
1626 
1627  /*******************************************************************************************************
1628  * Second IR in mode KSINV_IR_SIMPLE
1629  *******************************************************************************************************/
1630 
1631  /* N.B: The TR we pass in to ksinv_eval_nullti() will be from last UI evaluation.
1632  This may change when opautotr = TRUE, and a new TI2 will cause a new TR due to TI1 calcs below,
1633  which in turn will cause a new TI2 etc. Can this be made non-iteratitve ? */
1634  ksinv2_ti = ksinv_eval_nullti(exist(optr), (int) (*ksinv2_t1value * 1000.0) /* [ms]->[us] */, mainseqctrl->min_duration);
1635 
1636  status = ksinv_eval_duration(&ksinv2, ksinv2_ti, coreslice_momentstart);
1637  if (status != SUCCESS) return status;
1638 
1639  }
1640 
1641 
1642 
1644 
1645  /*******************************************************************************************************
1646  * First IR in mode KSINV_FLAIR_BLOCK or KSINV_FLAIR_T2PREP_BLOCK (T2-FLAIR)
1647  *******************************************************************************************************/
1648  int TR;
1649 
1650  if (opautotr == FALSE) { /* Manual TR */
1651  int filltr_duration;
1652 
1653  /* minTR: Call ksinv_eval_flairblock() first in AutoTR mode to get the minimum TR to report back to the UI, then proceed with the actual TR (optr)
1654  using ksinv_eval_flairblock_withmainupdate(), where we also update the main sequence duration */
1655  status = ksinv_eval_flairblock(&ksinv1, &filltr_duration, &minTR, &ksinv1_ti, TRUE, (opautoti) * (*ksinv1_t1value * 1000.0),
1656  ksinv2.seqctrl.duration + coreslice_momentstart, ksinv2.seqctrl.duration + coreslice_duration, slice_plan->nslices_per_pass);
1657 
1658  TR = exist(optr);
1659 
1660  /* Maximum slices that would fit the chosen manual TR */
1661  int i = 0;
1662  while (1) {
1663  /* N.B. arg 3 (TR) not modified in ksinv_eval_flairblock() when arg 5 (opautotr) = FALSE */
1664  status = ksinv_eval_flairblock(&ksinv1, &filltr_duration, &TR, &ksinv1_ti, FALSE, (opautoti) * (*ksinv1_t1value * 1000.0),
1665  ksinv2.seqctrl.duration + coreslice_momentstart, ksinv2.seqctrl.duration + coreslice_duration, slice_plan->nslices_per_pass + i);
1666  if (filltr_duration <= 0) {
1667  avmaxslquant = slice_plan->nslices_per_pass + i - 1; break;
1668  } else {
1669  i++;
1670  }
1671  }
1672 
1673  } /* Manual TR */
1674 
1675  status = ksinv_eval_flairblock_withmainupdate(&ksinv1, &ksinv_filltr, mainseqctrl, (opautotr) ? (&minTR) : (&TR),
1676  &ksinv1_ti, opautotr, (opautoti) * (*ksinv1_t1value * 1000.0),
1677  ksinv2.seqctrl.duration + coreslice_momentstart, ksinv2.seqctrl.duration + coreslice_duration, slice_plan->nslices_per_pass);
1678  if (status != SUCCESS) return status;
1679 
1680  if (opautotr) {
1681  /* show the optimal # slices to avoid inversion dummy inversion slices so the user can see what is the most time
1682  efficient number of slices (i.e. when scantime/slice is the lowest) */
1683  avmaxslquant = CEIL_DIV(slice_plan->nslices_per_pass, ksinv1.params.nflairslices) * ksinv1.params.nflairslices;
1684  } else if (existcv(optr)) {
1685  /* watch out for very narrow band of manual TR values between minTR and [minTR + nflairblocks*ksinv_filltr.ssi_time] where
1686  the sequence modules do not sum up to the intended optr since we have not been able to use the filltr sequence with this
1687  short duration. Increase the minTR to trigger an error */
1688  int nflairblocks = CEIL_DIV(slice_plan->nslices_per_pass, ksinv1.params.nflairslices); /* number of FLAIR blocks */
1689  if (TR > minTR) {
1690  minTR = CEIL_DIV(minTR + nflairblocks * ksinv_filltr.ssi_time, 1000) * 1000;
1691  }
1692  }
1693 
1694  /* add the fillTR sequence module to the sequence collection (ignored if ksinv_filltr.duration = 0) */
1696  if (status != SUCCESS) return status;
1697 
1698  } else if (ksinv1.params.irmode == KSINV_IR_SIMPLE && (opautotr == FALSE || opautoti == FALSE)) {
1699 
1700  /*******************************************************************************************************
1701  * First IR in mode KSINV_IR_SIMPLE and not both AutoTI and AutoTR
1702  *******************************************************************************************************/
1703 
1704  if (opautoti) {
1705  /* AutoTI: set TI based on ksinv1_t1value and current (manual) TR */
1706  ksinv1_ti = ksinv_eval_nullti(exist(optr), (int) (*ksinv1_t1value * 1000.0) /* [ms]->[us] */, mainseqctrl->min_duration);
1707  }
1708 
1709  /* set the sequence module duration */
1710  status = ksinv_eval_duration(&ksinv1, ksinv1_ti, coreslice_momentstart);
1711  if (status != SUCCESS) return status;
1712 
1713  /* calculate min TR given the ksinv_scan_sliceloop() duration and addition heating penalties */
1714  minTR = ksinv_eval_mintr(slice_plan, seqcollection, ks_gheatfact, &ksinv1, &ksinv2, NULL, play_coreslice, core_nargs, core_args);
1715  if (minTR == KS_NOTSET) return FAILURE;
1716 
1717  /* how much time to add due to long manual TR (opautotr = FALSE) or due to heating (opautotr = TRUE) */
1718  if (opautotr == FALSE) {
1719  timetoadd_perTR = exist(optr) - ksinv_scan_sliceloop(slice_plan, ks_scan_info, 0, &ksinv1, &ksinv2, NULL, KSINV_LOOP_NORMAL, play_coreslice, core_nargs, core_args);
1720  } else {
1721  timetoadd_perTR = minTR - ksinv_scan_sliceloop(slice_plan, ks_scan_info, 0, &ksinv1, &ksinv2, NULL, KSINV_LOOP_NORMAL, play_coreslice, core_nargs, core_args);
1722  }
1723 
1724  /* we spread the available timetoadd_perTR evenly, by increasing .duration of each slice by timetoadd_perTR/slice_plan->nslices_per_pass */
1725  mainseqctrl->duration += RUP_GRD(CEIL_DIV(timetoadd_perTR, slice_plan->nslices_per_pass));
1726 
1727 
1728  } else if ( ((ksinv1.params.irmode == KSINV_IR_SLICEAHEAD) && (ksinv2.params.irmode != KSINV_IR_SLICEAHEAD)) || ((ksinv1.params.irmode == KSINV_IR_SIMPLE) && (opautoti == TRUE) && (opautotr == TRUE)) ) {
1729 
1730  /*******************************************************************************************************
1731  * First IR, in mode
1732  * - KSINV_IR_SIMPLE with AutoTI and AutoTR
1733  * - KSINV_IR_SLICEAHEAD, when second IR was not KSINV_IR_SLICEAHEAD
1734  * For both cases, early heating control has been done
1735  *******************************************************************************************************/
1736 
1737  if (opautotr == FALSE || opautoti == FALSE) {
1738  return ks_error("%s: sliceahead mode requires both AutoTI and AutoTR", __FUNCTION__);
1739  }
1740 
1741  /* get sequence module duration, TR and TI based on T1 null value and coreslice duration */
1742  status = ksinv_eval_duration_t1value(&ksinv1, &minTR, &ksinv1_ti, ksinv1.params.approxti, coreslice_momentstart, coreslice_duration, mainseqctrl->min_duration, (int) (*ksinv1_t1value * 1000.0) /* [ms]->[us] */, slice_plan->nslices_per_pass);
1743  if (status != SUCCESS) return status;
1744 
1745  }
1746 
1747 
1748  /*******************************************************************************************************
1749  * update UI and GE globals
1750  *******************************************************************************************************/
1751 
1752  /* for AutoTI, update TI menu (first row) with the value in ksinv1_ti as well as opti */
1753  if (opautoti == TRUE) {
1754  pitival2 = ksinv1_ti;
1755  cvoverride(opti, ksinv1_ti, PSD_FIX_ON, PSD_EXIST_ON);
1756  }
1757 
1758  if (ksinv2.params.irmode != KSINV_OFF) { /* update opuser for IR2 T1-value with TI information */
1759  char tmpstr[200];
1760  sprintf(tmpstr, "IR2 - T1 to null (TI=%d ms)", ksinv2_ti / 1000);
1761  _cvdesc(_ksinv2_t1value, tmpstr);
1762 
1764  return ks_error("%s: IR2 must be shorter than IR1", __FUNCTION__);
1765  }
1766  }
1767 
1768  /* set npasses in slice plan to be consistent with nslices and nslices_per_pass */
1769  avmaxacqs = slice_plan->npasses; /* UI value ("# of Acqs:") */
1770 
1771  /* update min TR advisory */
1772  avmintr = minTR;
1773  avmaxtr = 100s;
1774 
1775  /* make sure TR in UI (optr) is long enough */
1776  if (opautotr == TRUE) {
1777 
1778  avmaxtr = minTR;
1779 
1780  cvoverride(optr, minTR, PSD_FIX_ON, PSD_EXIST_ON);
1781 
1783  avmaxslquant = slice_plan->nslices_per_pass;
1784  }
1785 
1786  } else if (existcv(optr) && (optr < minTR)) {
1787 
1788  return ks_error("%s: increase TR to %.1f ms (seq./heating limit)", __FUNCTION__, minTR / 1000.0);
1789 
1790  } else {
1791  if (avmaxslquant < slice_plan->nslices_per_pass) {
1792  /* avoid the max slices value in the UI to show up smaller than the prescribed slices/pass now that all is good */
1793  avmaxslquant = slice_plan->nslices_per_pass;
1794  }
1795  }
1796 
1797  /* prevent further addition of other sequence modules. Inversion must be last one added to the
1798  sequence collection to keep inversion timing correct */
1800 
1801  /* synonyms for optr: avail_image_time and act_tr */
1802  avail_image_time = RDN_GRD(exist(optr));
1804  ihtr = act_tr; /* image header TR */
1805  avminslquant = 1;
1806 
1807 
1808  /*******************************************************************************************************
1809  * Final SAR check
1810  *******************************************************************************************************/
1811  /* assure that we have taken care of TR timing and grad/RF heating issues so that we don't call GEReq_eval_TR() again
1812  This also prevents further addition of other sequence modules */
1813  seqcollection->evaltrdone = TRUE;
1814 
1815  /* Check TR timing and SAR limits */
1816  status = ksinv_eval_checkTR_SAR(seqcollection, slice_plan, play_coreslice, core_nargs, core_args);
1817  if (status != SUCCESS) return status;
1818 
1819 
1820 
1821 return SUCCESS;
1822 
1823 } /* ksinv_eval_multislice() */
STATUS ksinv_eval_flairblock(KSINV_SEQUENCE *ksinv, int *filltr_time, int *repetition_time, int *inversion_time, int autotr_flag, int T1tonull, int coreslice_momentstart, int coreslice_duration, int slperpass)
FLAIR block calculations
Definition: KSInversion.e:1354
int ksinv_eval_nullti(int TR, int T1value, int seqdur)
Calculates the TI value necessary to null the signal from a tissue with a given T1 value...
Definition: KSInversion.e:465
#define KS_NOTSET
Definition: KSFoundation.h:103
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
int32_t i
Definition: KSFoundation_tgt.c:1389
Definition: KSInversion.e:45
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
Definition: KSInversion.e:45
int momentstart
Definition: KSFoundation.h:1136
int mode
Definition: KSFoundation.h:1301
int duration
Definition: KSFoundation.h:1135
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
int nslicesahead
Definition: KSInversion.e:84
int ksinv1_ti
Definition: KSInversion.e:131
int irmode
Definition: KSInversion.e:76
int ksinv2_ti
Definition: KSInversion.e:132
int nslices_per_pass
Definition: KSFoundation.h:1353
STATUS ks_eval_seqcollection_durations_atleastminimum(KS_SEQ_COLLECTION *seqcollection) WARN_UNUSED_RESULT
Assures the .duration fields of all sequence modules being part of the sequence collection (KS_SEQ_CO...
Definition: KSFoundation_host.c:4348
int npasses
Definition: KSFoundation.h:1352
ifndef ACT_TR_EXISTS int act_tr
Definition: GERequired.e:210
STATUS ksinv_eval_flairblock_withmainupdate(KSINV_SEQUENCE *ksinv, KS_SEQ_CONTROL *ksinv_filltr, KS_SEQ_CONTROL *mainseqctrl, int *repetition_time, int *inversion_time, int autotr_flag, int T1tonull, int coreslice_momentstart, int coreslice_duration, int slperpass)
Definition: KSInversion.e:1459
int min_duration
Definition: KSFoundation.h:1132
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
_cvfloat * _ksinv2_t1value
Definition: KSInversion.e:147
STATUS ksinv_eval_checkTR_SAR(KS_SEQ_COLLECTION *seqcollection, KS_SLICE_PLAN *slice_plan, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
Runs the inversion slice loop and validates TR and SAR/hardware limits
Definition: KSInversion.e:1853
int ksinv_eval_mintr(const KS_SLICE_PLAN *slice_plan, KS_SEQ_COLLECTION *seqcollection, float gheatfact, KSINV_SEQUENCE *ksinv1, KSINV_SEQUENCE *ksinv2, KS_SEQ_CONTROL *ksinv_filltr, int(*play_coreslice)(const SCAN_INFO *, int, int, void **), int core_nargs, void **core_args)
Calculates the minimum TR allowed for the ksinv_scan_sliceloop()
Definition: KSInversion.e:1279
int nflairslices
Definition: KSInversion.e:85
STATUS ksinv_eval_duration_t1value(KSINV_SEQUENCE *ksinv, int *TR, int *TI, int approxti_flag, int coreslice_momentstart, int coreslice_duration, int mainseq_mindur, int T1value_toNull, int slperpass)
Sets the sequence module duration of a KSINV_SEQUENCE as well as TI and TR (slice-ahead IR)...
Definition: KSInversion.e:566
int ssi_time
Definition: KSFoundation.h:1134
int evaltrdone
Definition: KSFoundation.h:1303
float ks_gheatfact
Definition: GERequired.e:244
Definition: KSInversion.e:45
float * ksinv2_t1value
Definition: KSInversion.e:143
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
int avail_image_time
Definition: GERequired.e:208
Definition: KSInversion.e:47
STATUS ksinv_eval_duration(KSINV_SEQUENCE *ksinv, int TI, int coreslice_momentstart)
Definition: KSInversion.e:495
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
#define DEFAULT_AXIAL_SCAN_INFO
Definition: GERequired.e:153
KSINV_PARAMS params
Definition: KSInversion.e:101
float * ksinv1_t1value
Definition: KSInversion.e:142
Definition: KSFoundation.h:1974
Definition: KSInversion.e:45
Definition: KSInversion.e:45
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128
int approxti
Definition: KSInversion.e:82
#define _cvdesc(cv, string)
Definition: KSFoundation.h:106
endif SCAN_INFO ks_scan_info[SLTAB_MAX]
Definition: GERequired.e:215

◆ ksinv_check()

STATUS ksinv_check ( )

Checks related to inversion

Return values
STATUSSUCCESS or FAILURE
1879  {
1880 
1881  if (existcv(optr) && (opflair == OPFLAIR_INTERLEAVED) && (optr < KSINV_MINTR_T1FLAIR)) {
1882  ks_error("%s: TR should be >= %d ms for T1FLAIR", __FUNCTION__, KSINV_MINTR_T1FLAIR/1000);
1883  }
1884 
1885 return SUCCESS;
1886 
1887 }
#define KSINV_MINTR_T1FLAIR
Definition: KSInversion.e:57
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT

◆ ksinv_predownload_setrecon()

STATUS ksinv_predownload_setrecon ( )

Sets IR-related recon variables in predownload

Return values
STATUSSUCCESS or FAILURE
1898  {
1899 
1900  if ((ksinv1_mode != NULL) && ((int) *ksinv1_mode != KSINV_OFF)) {
1901  cvoverride(ihti, ksinv1_ti, PSD_FIX_ON, PSD_EXIST_ON); /* same as opti */
1902  }
1903 
1904  return SUCCESS;
1905 
1906 } /* ksinv_predownload_setrecon() */
float * ksinv1_mode
Definition: KSInversion.e:140
int ksinv1_ti
Definition: KSInversion.e:131
Definition: KSInversion.e:45

◆ ksinv_pulsegen()

void ksinv_pulsegen ( )

Generation of all inversion-related sequence modules

This function should be called directly from the pulsegen() function in a psd to create up to three sequence modules that can be used during scan.

N.B.: If ksinvX.seqctrl.duration = 0, both ksinv_pg() and KS_SEQLENGTH() will return early avoiding this sequence module to be created. Similarly for the seqInvFillTR wait sequence.

Returns
void
2077  {
2078 
2079  /* First (only) Inversion sequence module */
2080  ksinv_pg(&ksinv1);
2081  KS_SEQLENGTH(seqInv1, ksinv1.seqctrl); /* does nothing if ksinv1.seqctrl.duration = 0 */
2082 
2083  /* 2nd Inversion sequence module */
2084  ksinv_pg(&ksinv2);
2085  KS_SEQLENGTH(seqInv2, ksinv2.seqctrl); /* does nothing if ksinv2.seqctrl.duration = 0 */
2086 
2087  /* FillTR sequence for some inversion cases */
2088  KS_SEQLENGTH(seqInvFillTR, ksinv_filltr); /* does nothing if ksinv_filltr.duration = 0 */
2089 
2090 } /* ksinv_pulsegen() */
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
KS_SEQLENGTH(seq_name, seq_struct)
Creates a hardware sequence for the current sequence module
Definition: GERequired.e:65
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
int ksinv_pg(KSINV_SEQUENCE *)
Generation of the waveforms for the sequence objects in a KSINV_SEQUENCE
Definition: KSInversion.e:1937
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128

◆ ksinv_scan_seqstate()

STATUS ksinv_scan_seqstate ( KSINV_SEQUENCE ksinv,
const SCAN_INFO *  slice_info 
)

Sets the current state of a KSINV_SEQUENCE during scanning

This function sets the current state of all ksinv sequence objects being part of KSINV_SEQUENCE, specifically slice-dependent RF freq/phases changes.

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]ksinvPointer to KSINV_SEQUENCE
[in]slice_infoPointer to position of the slice to be played out (one element in the ks_scan_info[] array)
Return values
STATUSSUCCESS or FAILURE
2110  {
2111 
2112  if (ksinv == NULL) {
2113  return FAILURE;
2114  }
2115 
2116  if (ksinv->params.irmode == KSINV_OFF || ksinv->seqctrl.duration == 0)
2117  return SUCCESS;
2118 
2119  if (slice_info != NULL) {
2120 
2121  ks_scan_rotate(*slice_info);
2122 
2123  if (ksinv->params.irmode == KSINV_FLAIR_T2PREP_BLOCK) {
2124  ks_scan_rf_on(&ksinv->selrfexc.rf, INSTRALL);
2125  ks_scan_selrf_setfreqphase(&ksinv->selrfexc, INSTRALL, *slice_info, 0);
2126 
2127  ks_scan_rf_on(&ksinv->selrfrefoc.rf, INSTRALL);
2128  ks_scan_selrf_setfreqphase(&ksinv->selrfrefoc, INSTRALL, *slice_info, 90);
2129 
2130  ks_scan_rf_on(&ksinv->selrfinv.rf, INSTRALL);
2131  ks_scan_selrf_setfreqphase(&ksinv->selrfinv, INSTRALL, *slice_info, 0);
2132 
2133  ks_scan_rf_on(&ksinv->selrfflip.rf, INSTRALL);
2134  ks_scan_selrf_setfreqphase(&ksinv->selrfflip, INSTRALL, *slice_info, 0);
2135 
2136  } else {
2137  ks_scan_rf_on(&ksinv->selrfinv.rf, 0);
2138 
2140  ks_scan_selrf_setfreqphase_pins(&ksinv->selrfinv, 0, *slice_info,
2141  ksinv->selrfinv.sms_info.mb_factor, ksinv->selrfinv.sms_info.slice_gap, 0.0);
2142  } else {
2143  ks_scan_selrf_setfreqphase(&ksinv->selrfinv, 0, *slice_info, 0);
2144  }
2145  }
2146 
2147  } else {
2148 
2149  ks_scan_rf_off(&ksinv->selrfinv.rf, 0);
2150 
2151  }
2152 
2153  return SUCCESS;
2154 
2155 } /* ksinv_scan_seqstate() */
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 selrfinv
Definition: KSInversion.e:102
KS_SMS_INFO sms_info
Definition: KSFoundation.h:1494
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
float slice_gap
Definition: KSFoundation.h:1369
Definition: KSFoundation.h:1963
int duration
Definition: KSFoundation.h:1135
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 irmode
Definition: KSInversion.e:76
KS_SELRF selrfflip
Definition: KSInversion.e:105
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
KS_SELRF selrfexc
Definition: KSInversion.e:104
void ks_scan_selrf_setfreqphase_pins(KS_SELRF *selrf, int instanceno, SCAN_INFO sliceinfo, int sms_multiband_factor, float sms_slice_gap, float rfphase)
Updates the off-center phase-modulation of one or all instances of a PINS RF pulse (KS_SELRF)...
Definition: KSFoundation_tgt.c:504
void ks_scan_rotate(SCAN_INFO slice_info)
Performs a rotation of the logical system on hardware (WARP)
Definition: KSFoundation_tgt.c:989
int mb_factor
Definition: KSFoundation.h:1368
Definition: KSInversion.e:45
int pulse_type
Definition: KSFoundation.h:1370
KS_SELRF selrfrefoc
Definition: KSInversion.e:106
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45

◆ ksinv_scan_irslice()

int ksinv_scan_irslice ( KSINV_SEQUENCE ksinv,
const SCAN_INFO *  slice_pos 
)

Plays out one inversion slice in real time during scanning

On TGT on the MR system (PSD_HW), this function sets up (ksepi_scan_seqstate()) and plays out one KSINV_SEQUENCE. 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 ksepi_eval_tr()) we call ksepi_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 ksepi_scan_scantime(), which returns the total time of the entire scan.

Parameters
[in]ksinvPointer to KSINV_SEQUENCE
[in]slice_posPointer to position of the slice to be played out (one element in the ks_scan_info[] array)
Return values
irtimeTime taken in [us] to play out one inversion slice
2178  {
2179  SCAN_INFO slice_pos_updated;
2180  int time = 0;
2181  float tloc = 0.0;
2182 
2183  if (ksinv == NULL) {
2184  return 0;
2185  }
2186 
2187  if (ksinv->params.irmode != KSINV_OFF && ksinv->seqctrl.duration > 0) {
2188 
2189  if (slice_pos != NULL) {
2190  /* N.B.: Mphysical_inversion is an ipgexport KS_MAT4x4 variable that e.g. the main sequence can update in real time */
2191  ks_scan_update_slice_location(&slice_pos_updated, *slice_pos, Mphysical_inversion, NULL);
2192  tloc = slice_pos_updated.optloc;
2193  ksinv_scan_seqstate(ksinv, &slice_pos_updated);
2194  } else {
2195  ksinv_scan_seqstate(ksinv, slice_pos);
2196  }
2197 
2198  /* SMS offset */
2199  float offset = (ksinv->selrfinv.sms_info.slice_gap / 2) * (ksinv->selrfinv.sms_info.mb_factor - 1);
2200  float sms_slice_positions[ksinv->selrfinv.sms_info.mb_factor];
2201  int slice = 0;
2202  for (slice = 0; slice < ksinv->selrfinv.sms_info.mb_factor; ++slice) {
2203  if (slice_pos != NULL)
2204  sms_slice_positions[slice] = tloc + ksinv->selrfinv.sms_info.slice_gap * (0.5 + slice - (ksinv->selrfinv.sms_info.mb_factor / 2.0)) + offset;
2205  else
2206  sms_slice_positions[slice] = 0;
2207  }
2208 
2209  ks_plot_slicetime(&ksinv->seqctrl,
2210  ksinv->selrfinv.sms_info.mb_factor,
2211  sms_slice_positions,
2212  ksinv->selrfinv.slthick,
2213  slice_pos == NULL ? KS_PLOT_NO_EXCITATION : KS_PLOT_STANDARD);
2214 
2215  time += ks_scan_playsequence(&ksinv->seqctrl);
2216 
2217  }
2218 
2219  return time;
2220 
2221 } /* ksinv_scan_irslice() */
KS_SELRF selrfinv
Definition: KSInversion.e:102
KS_SMS_INFO sms_info
Definition: KSFoundation.h:1494
KS_SEQ_CONTROL seqctrl
Definition: KSInversion.e:100
float slice_gap
Definition: KSFoundation.h:1369
int duration
Definition: KSFoundation.h:1135
int irmode
Definition: KSInversion.e:76
STATUS ksinv_scan_seqstate(KSINV_SEQUENCE *ksinv, const SCAN_INFO *slice_info)
Sets the current state of a KSINV_SEQUENCE during scanning
Definition: KSInversion.e:2110
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1368
Definition: KSFoundation.h:336
Definition: KSFoundation.h:335
int mb_factor
Definition: KSFoundation.h:1368
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 ks_scan_update_slice_location(SCAN_INFO *new_loc, const SCAN_INFO orig_loc, const KS_MAT4x4 M_physical, const KS_MAT4x4 M_logical)
Updates a SCAN_INFO struct using physical and logical 4x4 transformation matrices
Definition: KSFoundation_common.c:3186
KSINV_PARAMS params
Definition: KSInversion.e:101
Definition: KSInversion.e:45
KS_MAT4x4 Mphysical_inversion
Definition: KSInversion.e:1922
float slthick
Definition: KSFoundation.h:1487

◆ ksinv_scan_sliceloop_nargs()

int ksinv_scan_sliceloop_nargs ( int  slperpass,
int  nargs,
void **  args 
)
2388  {
2389  KS_SLICE_PLAN slice_plan = KS_INIT_SLICEPLAN;
2390  slice_plan.nslices_per_pass = slperpass;
2391  SCAN_INFO *slice_positions = NULL;
2392  int passindx = 0;
2393  KSINV_SEQUENCE *ksinv1 = NULL;
2394  KSINV_SEQUENCE *ksinv2 = NULL;
2395  KS_SEQ_CONTROL *ksinv_filltr = NULL;
2396  KSINV_LOOP_MODE ksinv_loop_mode = KSINV_LOOP_NORMAL;
2397  int (*play_coreslice)(const SCAN_INFO *, int, int, void **) = 0;
2398  int core_nargs = 0;
2399  void **core_args = NULL;
2400 
2401  if (nargs < 0 || nargs > 3) {
2402  ks_error("%s: 3rd arg (void **) must contain 7 or 9 elements: slice_positions, passindx, &ksinv1, &ksinv2, &ksinv_filltr, play_as_dummy, play_coreslice [, core_nargs, core_args]", __FUNCTION__);
2403  return -1;
2404  } else if (nargs > 0 && args == NULL) {
2405  ks_error("%s: 3rd arg (void **) cannot be NULL if nargs (2nd arg) != 0", __FUNCTION__);
2406  return -1;
2407  }
2408 
2409  if (nargs >= 1 && args[0] != NULL) {
2410  slice_positions = (SCAN_INFO *) args[0];
2411  }
2412  if (nargs >= 2 && args[1] != NULL) {
2413  passindx = *((int *) args[1]);
2414  }
2415  if (nargs >= 3 && args[2] != NULL) {
2416  ksinv1 = (KSINV_SEQUENCE *) args[2];
2417  }
2418  if (nargs >= 4 && args[3] != NULL) {
2419  ksinv2 = (KSINV_SEQUENCE *) args[3];
2420  }
2421  if (nargs >= 5 && args[4] != NULL) {
2422  ksinv_filltr = (KS_SEQ_CONTROL *) args[4];
2423  }
2424  if (nargs >= 6 && args[5] != NULL) {
2425  ksinv_loop_mode = *((KSINV_LOOP_MODE *) args[5]);
2426  }
2427  if (nargs >= 7 && args[6] != NULL) {
2428  play_coreslice = (int (*)(const SCAN_INFO *, int, int, void **)) args[6];
2429  }
2430  if (nargs >= 8 && args[7] != NULL) {
2431  core_nargs = *((int *) args[7]);
2432  }
2433  if (nargs >= 9 && args[8] != NULL) {
2434  core_args = (void **) args[8];
2435  }
2436 
2437  return ksinv_scan_sliceloop(&slice_plan, slice_positions, passindx, ksinv1, ksinv2, ksinv_filltr, ksinv_loop_mode, play_coreslice, core_nargs, core_args); /* in [us] */
2438 
2439 } /* ksfse_scan_sliceloop_nargs() */
KSINV_LOOP_MODE
Definition: KSInversion.e:47
#define KS_INIT_SLICEPLAN
Definition: KSFoundation.h:249
Struct holding all information about slice locations and aquisition order
Definition: KSFoundation.h:1350
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
KSINV_SEQUENCE ksinv1
Definition: KSInversion.e:126
int nslices_per_pass
Definition: KSFoundation.h:1353
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
typedef struct holding all information about the KSInversion sequence module incl. all gradients and waveforms
Definition: KSInversion.e:98
KSINV_SEQUENCE ksinv2
Definition: KSInversion.e:127
Definition: KSInversion.e:47
A multi-purpose controller struct for each sequence module to facilitate RF scaling, SAR calculations, sequence duration and sequence switching
Definition: KSFoundation.h:1131
KS_SEQ_CONTROL ksinv_filltr
Definition: KSInversion.e:128

◆ ksspsat_pg()

STATUS ksspsat_pg ( KSSPSAT_SEQUENCE ksspsat)

The ksspsat (spatial sat) pulse sequence module

This is the spatial sat sequence module in ksspsat.e using the sequence objects in KSSPSAT_SEQUENCE with the sequence module name "ksspsat" (= ksspsat.seqctrl.description). On HOST, the minimum duration of the sequence module is set by ks_eval_seqctrl_setminduration().

691  {
692  STATUS status;
694  loc.pos = RUP_GRD(KS_RFSSP_PRETIME + 32);
695 
697  return SUCCESS;
698  }
699 
700 #ifdef IPG
701  /* TGT (IPG) only: return early if sequence module duration is zero */
702  if (ksspsat->seqctrl.duration == 0)
703  return SUCCESS;
704 #endif
705 
706  /* SelRF (including postgrad for spoiler) */
708  status = ks_pg_selrf(&ksspsat->selrf, loc, &ksspsat->seqctrl);
709  if (status != SUCCESS) return status;
710 
711  /* Optional spoiling using the postgrad trapezoid on the remaining two axes */
713  KS_SEQLOC tmploc = loc;
714  tmploc.pos += ksspsat->selrf.grad.duration;
715  switch (ksspsat->satlocation.gradboard) {
716  case XGRAD:
717  tmploc.board = YGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
718  tmploc.board = ZGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
719  break;
720  case YGRAD:
721  tmploc.board = XGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
722  tmploc.board = ZGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
723  break;
724  case ZGRAD:
725  tmploc.board = XGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
726  tmploc.board = YGRAD; status = ks_pg_trap(&ksspsat->selrf.postgrad, tmploc, &ksspsat->seqctrl); if (status != SUCCESS) return status;
727  break;
728  }
729  }
730 
732 
733  /*******************************************************************************************************
734  * Set the minimal sequence duration (ksspsat->seqctrl.min_duration) by calling
735  * ks_eval_seqctrl_setminduration()
736  *******************************************************************************************************/
737 
738  /* make sure we are divisible by GRAD_UPDATE_TIME (4us) */
739  loc.pos = RUP_GRD(loc.pos);
740 
741 #ifdef HOST_TGT
742  /* HOST only: Sequence duration (ksspsat->seqctrl.ssi_time must be > 0 and is added to ksspsat->seqctrl.min_duration in ks_eval_seqctrl_setminduration()
743  if ksspsat_params.satmode = KSSPSAT_OFF, then 2nd arg will be zero, making both ksspsat->seqctrl.min_duration and .duration = 0 */
745  ks_eval_seqctrl_setminduration(&ksspsat->seqctrl, loc.pos); /* loc.pos now corresponds to the end of last gradient in the sequence */
746 #endif
747 
748  return SUCCESS;
749 
750 } /* ksspsat_pg() */
KS_TRAP grad
Definition: KSFoundation.h:1491
KSSPSAT_LOC satlocation
Definition: KSSpSat.e:98
int pos
Definition: KSFoundation.h:389
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 board
Definition: KSFoundation.h:388
int ssi_time
Definition: KSSpSat.e:88
int duration
Definition: KSFoundation.h:1135
int gradboard
Definition: KSSpSat.e:74
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
#define KS_RFSSP_POSTTIME
Definition: KSFoundation.h:153
int spoilallaxes
Definition: KSSpSat.e:86
KS_SEQ_CONTROL seqctrl
Definition: KSSpSat.e:97
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
KSSPSAT_PARAMS ksspsat_params
Definition: KSSpSat.e:119
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:387
KS_TRAP postgrad
Definition: KSFoundation.h:1492
Definition: KSSpSat.e:41
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 active
Definition: KSSpSat.e:75
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:208
int duration
Definition: KSFoundation.h:585
KS_SELRF selrf
Definition: KSSpSat.e:99
#define KS_RFSSP_PRETIME
Definition: KSFoundation.h:152

◆ ksspsat_scan_seqstate()

void ksspsat_scan_seqstate ( KSSPSAT_SEQUENCE ksspsat,
float  rfphase 
)

Sets the current state of all ksspsat sequence objects being part of KSSPSAT_SEQUENCE

This function sets the current state of all ksspsat sequence objects being part of KSSPSAT_SEQUENCE, incl. gradient amplitude changes, RF freq/phase for the current slice position.

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.

Returns
void
805  {
806 #ifdef IPG
807 
811  }
812 
813 #endif
814 }
KSSPSAT_LOC satlocation
Definition: KSSpSat.e:98
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
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
void ks_scan_rotate(SCAN_INFO slice_info)
Performs a rotation of the logical system on hardware (WARP)
Definition: KSFoundation_tgt.c:989
Definition: KSSpSat.e:41
int active
Definition: KSSpSat.e:75
SCAN_INFO loc
Definition: KSSpSat.e:72
KS_SELRF selrf
Definition: KSSpSat.e:99

◆ ksspsat_init_params()

void ksspsat_init_params ( KSSPSAT_PARAMS params)

Resets the KSSPSAT_PARAMS struct (arg 1) to KSSPSAT_INIT_PARAMS

Parameters
[out]paramsPointer to the ksspsat params struct used to steer the behavior of this spsat sequence module
Returns
void
158  {
160  *params = defparams;
161 }
typedef struct holding steering parameters for KSSpSat
Definition: KSSpSat.e:81
#define KSSPSAT_INIT_PARAMS
Definition: KSSpSat.e:90

◆ ksspsat_init_sequence()

void ksspsat_init_sequence ( KSSPSAT_SEQUENCE ksspsat)

Resets the KSSPSAT_SEQUENCE struct (arg 1) to KSSPSAT_INIT_SEQUENCE

As KSSPSAT_INIT_SEQUENCE contains KSSPSAT_PARAMS, which sets the field .satmode = KSSPSAT_OFF, calling ksspsat_init_sequence() will disable the ksspsat sequence module (i.e. turn off spsat)

Parameters
[out]ksspsatPointer to KSSPSAT_SEQUENCE
Returns
void
175  {
177  *ksspsat = defseq;
178  strcpy(ksspsat->seqctrl.description, "ksspsat");
179 } /* ksspsat_init_sequence() */
#define KSSPSAT_INIT_SEQUENCE
Definition: KSSpSat.e:101
typedef struct holding all all gradients and waveforms for the KSSpSat sequence module
Definition: KSSpSat.e:95
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
KS_SEQ_CONTROL seqctrl
Definition: KSSpSat.e:97
KS_DESCRIPTION description
Definition: KSFoundation.h:1141

◆ ksspsat_eval_copycvs()

void ksspsat_eval_copycvs ( KSSPSAT_PARAMS params)

Copy CVs into a common params struct (KSSPSAT_PARAMS) used to steer this sequence module

Parameters
[out]paramsPointer to the ksspsat params struct used to steer the behavior of this spsat sequence module
Returns
void
192  {
193 
194  /* RF */
195  params->flip = ksspsat_flip;
196  params->rftype = ksspsat_rftype;
197 
198  /* SELRF postgrad (acting as spoiler after each SAT RF) */
200 
201  params->ssi_time = ksspsat_ssi_time;
202 
203  params->oblmethod = ksspsat_oblmethod;
204 
205 } /* ksspsat_eval_copycvs() */
int ksspsat_rftype
Definition: KSSpSat.e:132
float ksspsat_flip
Definition: KSSpSat.e:131
int ksspsat_ssi_time
Definition: KSSpSat.e:135
int ssi_time
Definition: KSSpSat.e:88
float spoilerscale
Definition: KSSpSat.e:85
float flip
Definition: KSSpSat.e:83
float ksspsat_spoilerscale
Definition: KSSpSat.e:133
int ksspsat_oblmethod
Definition: KSSpSat.e:137
int rftype
Definition: KSSpSat.e:84
int oblmethod
Definition: KSSpSat.e:87

◆ ksspsat_eval_numsats()

int ksspsat_eval_numsats ( KSSPSAT_SEQUENCE ksspsat)

Get number of Graphical (GRx) Sat pulses that are active in the UI

This function returns the number of graphical saturation pulses that have been explicitly placed out in the UI by the user. This includes both implicit and explicit sat bands. Implicit sat bands occur when the user selects a sat edge (S,I,A,P,R,L) of the FOV but does not click on the localizer image. Implicit sat bands are parallel to the logical axes and do not need a unique rotation matrix, and which FOV side to saturate is determined by the logical gradient axis choice (XGRAD, YGRAD, ZGRAD).

Parameters
[in]ksspsatPointer to KSSPSAT_SEQUENCE
Returns
numsats Number of GRx Sat pulses active in the UI
222  {
223  int i;
224  int n = 0;
225 
226  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++)
227  n += ksspsat[i].satlocation.active != KSSPSAT_OFF;
228 
229  return n;
230 
231 } /* ksspsat_eval_numsats() */
int32_t i
Definition: KSFoundation_tgt.c:1389
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
Definition: KSSpSat.e:41
Definition: KSSpSat.e:42

◆ ksspsat_eval_volborder()

STATUS ksspsat_eval_volborder ( KSSPSAT_VOLBORDER v)

Get the FOV volume borders in mm from the isocenter

Parameters
[out]vPointer to the KSSPSAT_VOLBORDER struct holding this information
Return values
STATUSSUCCESS or FAILURE
241  {
242  int i, nslices;
243 
244  if (KS_3D_SELECTED)
245  nslices = exist(opslquant) * exist(opvquant);
246  else
247  nslices = exist(opslquant);
248 
249  v->freq_min = scan_info[0].oprloc;
250  v->freq_max = scan_info[0].oprloc;
251  v->phase_min = scan_info[0].opphasoff;
252  v->phase_max = scan_info[0].opphasoff;
253  v->slice_min = scan_info[0].optloc;
254  v->slice_max = scan_info[0].optloc;
255 
256  for (i = 1; i < nslices; i++) {
257  if (scan_info[i].oprloc > v->freq_max)
258  v->freq_max = scan_info[i].oprloc;
259  else if (scan_info[i].oprloc < v->freq_min)
260  v->freq_min = scan_info[i].oprloc;
261 
262  if (scan_info[i].opphasoff > v->phase_max)
263  v->phase_max = scan_info[i].opphasoff;
264  else if (scan_info[i].opphasoff < v->phase_min)
265  v->phase_min = scan_info[i].opphasoff;
266 
267  if (scan_info[i].optloc > v->slice_max)
268  v->slice_max = scan_info[i].optloc;
269  else if (scan_info[i].optloc < v->slice_min)
270  v->slice_min = scan_info[i].optloc;
271  }
272 
273  v->freq_min -= exist(opfov) / 2.0;
274  v->freq_max += exist(opfov) / 2.0;
275  v->phase_min -= (exist(opfov) * exist(opphasefov)) / 2.0;
276  v->phase_max += (exist(opfov) * exist(opphasefov)) / 2.0;
277  v->slice_min -= exist(opslthick) / 2.0;
278  v->slice_max += exist(opslthick) / 2.0;
279 
280  return SUCCESS;
281 
282 } /* ksspsat_eval_volborder() */
float phase_max
Definition: KSSpSat.e:62
#define KS_3D_SELECTED
Definition: KSFoundation.h:177
int32_t i
Definition: KSFoundation_tgt.c:1389
float opfov
float slice_min
Definition: KSSpSat.e:63
float phase_min
Definition: KSSpSat.e:61
float slice_max
Definition: KSSpSat.e:64
float freq_min
Definition: KSSpSat.e:59
float freq_max
Definition: KSSpSat.e:60
float opslthick

◆ ksspsat_eval_satplacements_from_UI()

STATUS ksspsat_eval_satplacements_from_UI ( KSSPSAT_SEQUENCE ksspsat,
KSSPSAT_PARAMS params 
)

Populate the satlocation field of the KSSPSAT_PARAMS struct

This function gets information from the UI regarding the sat pulses, whether they are implicit or explicit, their thickness and offset, and for explicit pulses also the rotation matrix.

The user can select up to 6 sat band in total in the UI, which may be only implicit or explicit, or a mix of both. First, information on the implicit sat pulses is collected by checking for the CVs opsatx etc. (managed by the host interface, i.e. the UI). The UI maps opsatx to frequency encoding (despite that the sat is expressed in patient terms: Superior, Inferior, etc.), and correspondingly opsaty maps to the phase encoding direction and opsatz to the slice direction.

When two oppositely placed implicit sat bands have different thickness, opsatx (and opsaty/opsatz) is set to KSSPSAT_PARA (4), indicating that two separate RF pulses should be played out. When two oppositely placed implicit sat bands have the same thickness, opsatx = KSSPSAT_HAD (3), which is an indication for that a single hadamard RF pulse should be used to saturate both sides. This is not yet supported, so for now both KSSPSAT_HAD and KSSPSAT_PARA will result in two separate RF pulses.

If the user selects one of the sat band buttons (S,I,A,P,R,L), and then also clicks on the localizer image, the implicit sat (one of S,I,A,P,R,L) is now replaced with an explicit sat. The UI sets then the corresponding opsatx/y/z to 0, and sets instead one of the bits in the bitmask CV opexsatmask.

Explicit sat bands receives the rotation information from the transpose of eg_sat_rot instead of the scan_info struct, slice selection is always ZGRAD, the thickness is taken from opexsatthick1-6, and the slice offset from opexsatloc1-6.

Parameters
[in,out]ksspsatPointer to KSSPSAT_SEQUENCE
[in]paramsPointer to the ksspsat params struct used to steer the behavior of this spsat sequence module
Return values
STATUSSUCCESS or FAILURE
319  {
320  STATUS status;
321  int i, j;
322  float sat_info[6][9];
323 
324 
325  /***************** IMPLICIT SAT (at the FOV edges) *****************/
326 
327 
328  /* Determine FOV box */
329  status = ksspsat_eval_volborder(&params->volborder);
330  if (status != SUCCESS) return status;
331 
332  /* Init all sat bands to off state */
333  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++)
334  ksspsat[i].satlocation.active = KSSPSAT_OFF;
335 
336  /* Init all sat rotations to scan plane */
337  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++)
338  memcpy(ksspsat[i].satlocation.loc.oprot, scan_info[0].oprot, 9 * sizeof(float));
339 
340  /* Implicit sat thicknesses */
341  ksspsat[KSSPSAT_1].satlocation.thickness = (float) exist(opdfsathick1);
342  ksspsat[KSSPSAT_2].satlocation.thickness = (float) exist(opdfsathick2);
343  ksspsat[KSSPSAT_3].satlocation.thickness = (float) exist(opdfsathick3);
344  ksspsat[KSSPSAT_4].satlocation.thickness = (float) exist(opdfsathick4);
345  ksspsat[KSSPSAT_5].satlocation.thickness = (float) exist(opdfsathick5);
346  ksspsat[KSSPSAT_6].satlocation.thickness = (float) exist(opdfsathick6);
347 
348 
349  /* Implicit Sat(s) - Frequency encoding direction */
350  if (opsatx == KSSPSAT_POS || opsatx == KSSPSAT_PARA || opsatx == KSSPSAT_HAD) {
354  }
355  if (opsatx == KSSPSAT_NEG || opsatx == KSSPSAT_PARA || opsatx == KSSPSAT_HAD) {
359  }
360 
361  /* Implicit Sat(s) - Phase encoding direction */
362  if (opsaty == KSSPSAT_POS || opsaty == KSSPSAT_PARA || opsaty == KSSPSAT_HAD) {
366  }
367  if (opsaty == KSSPSAT_NEG || opsaty == KSSPSAT_PARA || opsaty == KSSPSAT_HAD) {
371  }
372 
373  /* Implicit Sat(s) - Slice direction */
374  if (opsatz == KSSPSAT_POS || opsatz == KSSPSAT_PARA || opsatz == KSSPSAT_HAD) {
378  }
379  if (opsatz == KSSPSAT_NEG || opsatz == KSSPSAT_PARA || opsatz == KSSPSAT_HAD) {
383  }
384 
385 
386 
387  /***************** EXPLICIT SAT (manually placed) *****************/
388 
389 
390  /* matrix transpose */
391  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
392  sat_info[i][0] = eg_sat_rot[i][0];
393  sat_info[i][1] = eg_sat_rot[i][3];
394  sat_info[i][2] = eg_sat_rot[i][6];
395  sat_info[i][3] = eg_sat_rot[i][1];
396  sat_info[i][4] = eg_sat_rot[i][4];
397  sat_info[i][5] = eg_sat_rot[i][7];
398  sat_info[i][6] = eg_sat_rot[i][2];
399  sat_info[i][7] = eg_sat_rot[i][5];
400  sat_info[i][8] = eg_sat_rot[i][8];
401  }
402 
403  int exsat_mask = 1;
404  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++, exsat_mask = exsat_mask << 1) {
405 
406  /* 0-5: I, S, P, A, L, R */
407  if (opexsatmask & exsat_mask) {
408 
409  int freeslot = KS_NOTSET;
410 
411  for (j = 0; j < KSSPSAT_MAXNUMSAT; j++) {
412  if (ksspsat[j].satlocation.active == KSSPSAT_OFF) {
413  freeslot = j;
414  break;
415  }
416  }
417  if (freeslot == KS_NOTSET) {
418  return ks_error("%s: No free slots for explicit sat", __FUNCTION__);
419  }
420 
421  /* mark as explicit sat */
423 
424  /* copy rotation matrix from sat_info[][] array set up by the host interface (not the psd) */
425  memcpy(ksspsat[freeslot].satlocation.loc.oprot, sat_info[i], 9 * sizeof(float));
426 
427  /* Always ZGRAD since we are setting the slice angle via the rotation matrix for explicit sat */
428  ksspsat[freeslot].satlocation.gradboard = ZGRAD;
429 
430  /* Transmit location and thickness from CVs set by the host interface (not the psd) */
431  if (i == KSSPSAT_1) {
432  ksspsat[freeslot].satlocation.thickness = opexsathick1;
433  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc1;
434  } else if (i == KSSPSAT_2) {
435  ksspsat[freeslot].satlocation.thickness = opexsathick2;
436  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc2;
437  } else if (i == KSSPSAT_3) {
438  ksspsat[freeslot].satlocation.thickness = opexsathick3;
439  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc3;
440  } else if (i == KSSPSAT_4) {
441  ksspsat[freeslot].satlocation.thickness = opexsathick4;
442  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc4;
443  } else if (i == KSSPSAT_5) {
444  ksspsat[freeslot].satlocation.thickness = opexsathick5;
445  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc5;
446  } else if (i == KSSPSAT_6) {
447  ksspsat[freeslot].satlocation.thickness = opexsathick6;
448  ksspsat[freeslot].satlocation.loc.optloc = opexsatloc6;
449  }
450 
451  }
452  }
453 
454 
455  return SUCCESS;
456 
457 } /* ksspsat_eval_satplacements_from_UI() */
float phase_max
Definition: KSSpSat.e:62
Definition: KSSpSat.e:43
Definition: KSSpSat.e:43
KSSPSAT_LOC satlocation
Definition: KSSpSat.e:98
#define KS_NOTSET
Definition: KSFoundation.h:103
Definition: KSSpSat.e:43
Definition: KSSpSat.e:43
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
KSSPSAT_VOLBORDER volborder
Definition: KSSpSat.e:82
int32_t i
Definition: KSFoundation_tgt.c:1389
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
STATUS ksspsat_eval_volborder(KSSPSAT_VOLBORDER *v)
Get the FOV volume borders in mm from the isocenter
Definition: KSSpSat.e:241
int gradboard
Definition: KSSpSat.e:74
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
float slice_min
Definition: KSSpSat.e:63
float phase_min
Definition: KSSpSat.e:61
Definition: KSSpSat.e:41
Definition: KSSpSat.e:42
int active
Definition: KSSpSat.e:75
float slice_max
Definition: KSSpSat.e:64
float freq_min
Definition: KSSpSat.e:59
float freq_max
Definition: KSSpSat.e:60
Definition: KSSpSat.e:41
SCAN_INFO loc
Definition: KSSpSat.e:72
Definition: KSSpSat.e:41
float thickness
Definition: KSSpSat.e:73

◆ ksspsat_eval_satplacements_dump()

STATUS ksspsat_eval_satplacements_dump ( KSSPSAT_SEQUENCE ksspsat,
KSSPSAT_PARAMS params 
)

Writes out the geometric information of the active sat bands to spsat.txt

On the MR system (PSD_HW), this file will be located in /usr/g/mrraw, while in simulation it will be located in the current psd directory.

Parameters
[in]ksspsatPointer to KSSPSAT_SEQUENCE
[in]paramsPointer to the ksspsat params struct used to steer the behavior of this spsat sequence module
Return values
STATUSSUCCESS or FAILURE
474  {
475  float *rot;
476  int i;
477 
478 #ifdef PSD_HW
479  FILE *fp = fopen("/usr/g/mrraw/spsat.txt", "w");
480 #else
481  FILE *fp = fopen("./spsat.txt", "w");
482 #endif
483 
484  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
485  fprintf(fp, "Sat Pulse #%d: ", i);
486  if (ksspsat[i].satlocation.active == KSSPSAT_OFF)
487  fprintf(fp, "Off\n");
488  else if (ksspsat[i].satlocation.active == KSSPSAT_EXPLICIT)
489  fprintf(fp, "Explicit\n");
490  else if (ksspsat[i].satlocation.active == KSSPSAT_IMPLICIT)
491  fprintf(fp, "Implicit\n");
492 
493  fprintf(fp, "Grad: ");
494  if (ksspsat[i].satlocation.gradboard == XGRAD)
495  fprintf(fp, "XGRAD (Freq)");
496  else if (ksspsat[i].satlocation.gradboard == YGRAD)
497  fprintf(fp, "YGRAD (Phase)");
498  else if (ksspsat[i].satlocation.gradboard == ZGRAD)
499  fprintf(fp, "ZGRAD (Slice)");
500 
501  fprintf(fp, "\nThickness: %.2f\n", ksspsat[i].satlocation.thickness);
502  fprintf(fp, "Location: %.2f\n", ksspsat[i].satlocation.loc.optloc);
503 
504  rot = ksspsat[i].satlocation.loc.oprot;
505  fprintf(fp, "Rotation:\n");
506  fprintf(fp, "%.3f %.3f %.3f\n%.3f %.3f %.3f\n%.3f %.3f %.3f\n\n", rot[0], rot[3], rot[6], rot[1], rot[4], rot[7], rot[2], rot[5], rot[8]);
507  }
508 
509  fprintf(fp, "Volume borders:\n- Freq: %.2f %.2f\n- Phase: %.2f %.2f\n- Slice: %.2f %.2f\n", params->volborder.freq_min, params->volborder.freq_max, params->volborder.phase_min, params->volborder.phase_max, params->volborder.slice_min, params->volborder.slice_max);
510 
511  rot = scan_info[0].oprot;
512  fprintf(fp, "\nSlice rotation:\n");
513  fprintf(fp, "%.3f %.3f %.3f\n%.3f %.3f %.3f\n%.3f %.3f %.3f\n\n", rot[0], rot[3], rot[6], rot[1], rot[4], rot[7], rot[2], rot[5], rot[8]);
514 
515 
516 
517  fclose(fp);
518 
519  return SUCCESS;
520 
521 }
float phase_max
Definition: KSSpSat.e:62
KSSPSAT_LOC satlocation
Definition: KSSpSat.e:98
KSSPSAT_VOLBORDER volborder
Definition: KSSpSat.e:82
int32_t i
Definition: KSFoundation_tgt.c:1389
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
float slice_min
Definition: KSSpSat.e:63
float phase_min
Definition: KSSpSat.e:61
Definition: KSSpSat.e:41
Definition: KSSpSat.e:42
float slice_max
Definition: KSSpSat.e:64
float freq_min
Definition: KSSpSat.e:59
float freq_max
Definition: KSSpSat.e:60
Definition: KSSpSat.e:41
SCAN_INFO loc
Definition: KSSpSat.e:72
Definition: KSSpSat.e:41

◆ ksspsat_eval_loggrd()

STATUS ksspsat_eval_loggrd ( LOG_GRAD *  satloggrd,
SCAN_INFO *  slice_info,
int  satoblmethod 
)

Assigns a loggrd structure specific to the spatial saturation sequence module

Parameters
[out]satloggrdPointer to LOG_GRAD
[in]slice_infoPointer to SCAN_INFO, holding rotation information about current sat slice
[in]satoblmethodPSD_OBL_RESTRICT or PSD_OBL_OPTIMAL
Return values
STATUSSUCCESS or FAILURE
535  {
536  int initnewgeo = 1;
537 
538  /* copy loggrd from GERequired.e */
539  *satloggrd = loggrd;
540 
541  if (obloptimize(satloggrd, &phygrd, slice_info, 1, ((satoblmethod == PSD_OBL_RESTRICT) ? 4 /*oblique plane*/ : opphysplane), exist(opcoax),
542  (int) satoblmethod, exist(obl_debug), &initnewgeo, cfsrmode) == FAILURE) {
543  return ks_error("%s: obloptimize failed", __FUNCTION__);
544  }
545 
546  return SUCCESS;
547 
548 }
STATUS ks_error(const char *format,...) __attribute__((format(printf
Common error message function for HOST and TGT
PHYS_GRAD phygrd
LOG_GRAD loggrd
int obl_debug
Definition: GERequired.e:233
int cfsrmode

◆ ksspsat_eval_setupobjects()

STATUS ksspsat_eval_setupobjects ( )

Sets up the sequence objects for the spatial sat sequence module (KSSPSAT_SEQUENCE ksspsat)

This spatial sat sequence module consists of an RF pulse (selectable via ksspsat_params.rftype.

Return values
STATUSSUCCESS or FAILURE
561  {
562  STATUS status;
563  int i;
564 
566  if (status != SUCCESS) return status;
567 
568  if (ksspsat_debug) {
570  if (status != SUCCESS) return status;
571  }
572 
573  /* Fill in the struct ksspsat_params based on corresponding ksspsat_*** CVs (see CV section)
574  The CVs should only be used to steer the content of field .params, which in turn should control further decisions */
576 
577  if (! ksspsat_eval_numsats(ksspsat)) {
578  return SUCCESS;
579  }
580 
581  /* up to 6 (KSSPSAT_MAXNUMSAT) selective RF pulses */
582  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
583 
584  if (ksspsat[i].satlocation.active != KSSPSAT_OFF) {
585  char tmpstr[100];
587  ksspsat[i].selrf.rf = spsatc_satqptbw12; /* Complex Sat RF pulse. KSFoundation_GERF.h */
588  } else {
589  ksspsat[i].selrf.rf = spsat_dblsatl0; /* SLR Sat RF pulse. KSFoundation_GERF.h */
590  }
593  ksspsat[i].selrf.crusherscale = ksspsat_params.spoilerscale; /* as rf role is KS_RF_ROLE_SPSAT, only postgrad will be active */
594  sprintf(tmpstr, "ksspsat%d_selrf", i+1);
595 
596  /* obloptimize sat (satloggrd declared in epic.h) */
597  ksspsat_eval_loggrd(&satloggrd, &ksspsat[i].satlocation.loc, ksspsat_params.oblmethod);
598 
599  if (ks_eval_selrf_constrained(&ksspsat[i].selrf, tmpstr, ks_syslimits_ampmax(satloggrd), ks_syslimits_slewrate(satloggrd)) == FAILURE)
600  return FAILURE;
601 
602 
603  /* setup seqctrl with desired SSI time and zero duration. .min_duration will be set in ksspsat_pg() */
605  sprintf(tmpstr, "ksspsat%d", i+1);
606  strcpy(ksspsat[i].seqctrl.description, tmpstr);
607 
608  } /* if active */
609 
610 
611  } /* for KSSPSAT_MAXNUMSAT */
612 
613 
614  return SUCCESS;
615 
616 } /* ksspsat_eval_setupobjects() */
int ksspsat_eval_numsats(KSSPSAT_SEQUENCE *ksspsat)
Get number of Graphical (GRx) Sat pulses that are active in the UI
Definition: KSSpSat.e:222
KSSPSAT_LOC satlocation
Definition: KSSpSat.e:98
float ks_syslimits_ampmax(LOG_GRAD loggrd)
Returns the maximum gradient amplitude that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:201
void ksspsat_eval_copycvs(KSSPSAT_PARAMS *params)
Copy CVs into a common params struct (KSSPSAT_PARAMS) used to steer this sequence module...
Definition: KSSpSat.e:192
STATUS ksspsat_eval_satplacements_from_UI(KSSPSAT_SEQUENCE *ksspsat, KSSPSAT_PARAMS *params)
Populate the satlocation field of the KSSPSAT_PARAMS struct
Definition: KSSpSat.e:319
int32_t i
Definition: KSFoundation_tgt.c:1389
STATUS ks_eval_selrf_constrained(KS_SELRF *selrf, const char *const desc, float ampmax, float slewrate) WARN_UNUSED_RESULT
Sets up a KS_SELRF object for RF slice selection, subject to gradients constraints specified as input...
Definition: KSFoundation_host.c:2827
STATUS ksspsat_eval_satplacements_dump(KSSPSAT_SEQUENCE *ksspsat, KSSPSAT_PARAMS *params)
Writes out the geometric information of the active sat bands to spsat.txt
Definition: KSSpSat.e:474
float spoilerscale
Definition: KSSpSat.e:85
float flip
Definition: KSSpSat.e:83
float flip
Definition: KSFoundation.h:940
int ksspsat_debug
Definition: KSSpSat.e:136
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
STATUS ksspsat_eval_loggrd(LOG_GRAD *satloggrd, SCAN_INFO *slice_info, int satoblmethod)
Assigns a loggrd structure specific to the spatial saturation sequence module
Definition: KSSpSat.e:535
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
KS_RF rf
Definition: KSFoundation.h:1485
Definition: KSSpSat.e:44
KS_SEQ_CONTROL seqctrl
Definition: KSSpSat.e:97
KSSPSAT_PARAMS ksspsat_params
Definition: KSSpSat.e:119
Definition: KSSpSat.e:41
float ks_syslimits_slewrate(LOG_GRAD loggrd)
Returns the maximum slewrate that can be used on all gradient boards simultaneously
Definition: KSFoundation_common.c:248
DECL_TYPE KS_RF spsatc_satqptbw12
Definition: KSFoundation_GERF.c:150
int rftype
Definition: KSSpSat.e:84
DECL_TYPE KS_RF spsat_dblsatl0
Definition: KSFoundation_GERF.c:147
Definition: KSSpSat.e:42
float crusherscale
Definition: KSFoundation.h:1488
int oblmethod
Definition: KSSpSat.e:87
float slthick
Definition: KSFoundation.h:1487
KS_SELRF selrf
Definition: KSSpSat.e:99
float thickness
Definition: KSSpSat.e:73

◆ ksspsat_eval()

STATUS ksspsat_eval ( KS_SEQ_COLLECTION seqcollection)

Spatial Sat evaluation function, to be called from the cveval() function of the main sequence

This function calls ksspsat_eval_setupobjects() to design the RF pulse and spoiler for this spatial sat sequence module. It then calls ksspsat_pg() to determine the (minimum) sequence module duration. Finally, the sequence module ksspsat is added to the sequence collection struct passed in from the cveval() function of the main sequence.

Parameters
[in,out]seqcollectionPointer to the KS_SEQ_COLLECTION struct holding all sequence modules
Return values
STATUSSUCCESS or FAILURE
633  {
634  STATUS status;
635  int i;
636 
637  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
639  }
640 
641  status = ksspsat_eval_setupobjects();
642  if (status != SUCCESS) return status;
643 
644  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
645 
646  if (ksspsat[i].satlocation.active != KSSPSAT_OFF) {
647 
648  status = ksspsat_pg(&ksspsat[i]);
649  if (status != SUCCESS) return status;
650 
651  /* ks_eval_addtoseqcollection() will only add to collection if ksspsat.seqctrl.duration > 0 */
652  status = ks_eval_addtoseqcollection(seqcollection, &ksspsat[i].seqctrl);
653  if (status != SUCCESS) return status;
654 
655  } /* if active */
656 
657  }
658 
659  return status;
660 
661 } /* ksspsat_eval() */
void ksspsat_init_sequence(KSSPSAT_SEQUENCE *ksspsat)
Resets the KSSPSAT_SEQUENCE struct (arg 1) to KSSPSAT_INIT_SEQUENCE
Definition: KSSpSat.e:175
int32_t i
Definition: KSFoundation_tgt.c:1389
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
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
Definition: KSSpSat.e:41
Definition: KSSpSat.e:42
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:80
STATUS ksspsat_eval_setupobjects()
Sets up the sequence objects for the spatial sat sequence module (KSSPSAT_SEQUENCE ksspsat)...
Definition: KSSpSat.e:561
int ksspsat_pg(KSSPSAT_SEQUENCE *ksspsat)
The ksspsat (spatial sat) pulse sequence module
Definition: KSSpSat.e:691

◆ ksspsat_pulsegen()

STATUS ksspsat_pulsegen ( )
754  {
755  int i;
756 
757  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
758  if (ksspsat[i].satlocation.active != KSSPSAT_OFF) {
759 
760  ksspsat_pg(&ksspsat[i]);
761 
762  switch (i) {
763  case KSSPSAT_1:
764  KS_SEQLENGTH(seqKSSpSat1, ksspsat[i].seqctrl);
765  break;
766  case KSSPSAT_2:
767  KS_SEQLENGTH(seqKSSpSat2, ksspsat[i].seqctrl);
768  break;
769  case KSSPSAT_3:
770  KS_SEQLENGTH(seqKSSpSat3, ksspsat[i].seqctrl);
771  break;
772  case KSSPSAT_4:
773  KS_SEQLENGTH(seqKSSpSat4, ksspsat[i].seqctrl);
774  break;
775  case KSSPSAT_5:
776  KS_SEQLENGTH(seqKSSpSat5, ksspsat[i].seqctrl);
777  break;
778  case KSSPSAT_6:
779  KS_SEQLENGTH(seqKSSpSat6, ksspsat[i].seqctrl);
780  break;
781  }
782 
783  }
784  }
785 
786  return SUCCESS;
787 }
KS_SEQLENGTH(seq_name, seq_struct)
Creates a hardware sequence for the current sequence module
Definition: GERequired.e:65
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
int32_t i
Definition: KSFoundation_tgt.c:1389
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
Definition: KSSpSat.e:42
Definition: KSSpSat.e:42
Definition: KSSpSat.e:41
Definition: KSSpSat.e:42
int ksspsat_pg(KSSPSAT_SEQUENCE *ksspsat)
The ksspsat (spatial sat) pulse sequence module
Definition: KSSpSat.e:691

◆ ksspsat_scan_playsequences()

int ksspsat_scan_playsequences ( int  perform_slicetimeplot)
819  {
820  int i;
821  int time = 0;
822  static int counter = 0;
823 
824  float rfphase = ks_scan_rf_phase_spoiling(counter++);
825 
826  for (i = 0; i < KSSPSAT_MAXNUMSAT; i++) {
827 
828  ksspsat_scan_seqstate(&ksspsat[i], rfphase);
829 
830  time += ks_scan_playsequence(&ksspsat[i].seqctrl);
831 
832  if (perform_slicetimeplot) {
833  /* spatial sat not necessarily in the slice direction, so can't trust its thickness or direction.
834  save it as 1000 mm thick at center (0) for now just to be able to mark it in time in the plot */
835  ks_plot_slicetime(&ksspsat[i].seqctrl, 1, NULL, KS_NOTSET, KS_PLOT_STANDARD);
836  }
837 
838  }
839 
840  return time;
841 }
float ks_scan_rf_phase_spoiling(int counter)
Returns spoiling phase for a given RF counter
Definition: KSFoundation_common.c:3883
void ksspsat_scan_seqstate(KSSPSAT_SEQUENCE *ksspsat, float rfphase)
Sets the current state of all ksspsat sequence objects being part of KSSPSAT_SEQUENCE
Definition: KSSpSat.e:805
#define KS_NOTSET
Definition: KSFoundation.h:103
int32_t i
Definition: KSFoundation_tgt.c:1389
KSSPSAT_SEQUENCE ksspsat[KSSPSAT_MAXNUMSAT]
Definition: KSSpSat.e:118
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1368
Definition: KSFoundation.h:335
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
Definition: KSSpSat.e:42

Variable Documentation

◆ kschemsat

◆ kschemsat_flag

int kschemsat_flag = KSCHEMSAT_OFF with {KSCHEMSAT_OFF, KSCHEMSAT_WATER, KSCHEMSAT_OFF, VIS, "flag for kschemsat (0:Off 1:FatSat 2:WaterSat)",}

◆ kschemsat_flip

float kschemsat_flip = KSCHEMSAT_DEFAULT_FLIP with {0, 360, KSCHEMSAT_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}

◆ kschemsat_rftype

int kschemsat_rftype = KSCHEMSAT_RF_STD with {KSCHEMSAT_RF_STD, KSCHEMSAT_RF_SINC, KSCHEMSAT_RF_STD, VIS, "RF type (0:Std 1:Sinc)",}

◆ kschemsat_sinc_bw

int kschemsat_sinc_bw = KSCHEMSAT_DEFAULT_SINCRF_BW_3T with {2, 100000, 300, VIS, "Sinc RF BW",}

◆ kschemsat_sinc_tbp

int kschemsat_sinc_tbp = KSCHEMSAT_DEFAULT_SINCRF_TBP with {2, 20, 2, VIS, "Sinc RF Time-Bandwidth-Product",}

◆ kschemsat_rfoffset

int kschemsat_rfoffset = 0 with {-1000, 1000, 0, VIS, "RF excitation freq offset [Hz]",}

◆ kschemsat_spoilerarea

float kschemsat_spoilerarea = KSCHEMSAT_DEFAULT_SPOILERAREA with {0, 10000, KSCHEMSAT_DEFAULT_SPOILERAREA, VIS, "Spoiler area",}

◆ kschemsat_ssi_time

int kschemsat_ssi_time = KSCHEMSAT_DEFAULT_SSITIME with {10, 20000, KSCHEMSAT_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}

◆ ksinv1

◆ ksinv2

◆ ksinv_filltr

◆ ksinv1_ti

int ksinv1_ti = 0

◆ ksinv2_ti

int ksinv2_ti = 0

◆ use_ir1_mode

int use_ir1_mode = 0

◆ use_ir1_t1

int use_ir1_t1 = 0

◆ use_ir2_mode

int use_ir2_mode = 0

◆ use_ir2_t1

int use_ir2_t1 = 0

◆ ksinv1_mode

float* ksinv1_mode = NULL

◆ ksinv2_mode

float* ksinv2_mode = NULL

◆ ksinv1_t1value

float* ksinv1_t1value = NULL

◆ ksinv2_t1value

float* ksinv2_t1value = NULL

◆ _ksinv1_mode

_cvfloat* _ksinv1_mode = NULL

◆ _ksinv2_mode

_cvfloat* _ksinv2_mode = NULL

◆ _ksinv1_t1value

_cvfloat* _ksinv1_t1value = NULL

◆ _ksinv2_t1value

_cvfloat* _ksinv2_t1value = NULL

◆ ksinv_ssi_time

int ksinv_ssi_time = KSINV_DEFAULT_SSITIME with {10, 20000, KSINV_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}

◆ ksinv_filltr_ssi_time

int ksinv_filltr_ssi_time = KSINV_FILLTR_SSITIME with {10, 20000, KSINV_FILLTR_SSITIME, VIS, "Time from eos to ssi in intern trig",}

◆ ksinv_mintr_t2flair

int ksinv_mintr_t2flair = KSINV_MINTR_T2FLAIR with {0, 30s, KSINV_MINTR_T2FLAIR, VIS, "Min TR for T2-FLAIR",}

◆ ksinv_mintr_t1flair

int ksinv_mintr_t1flair = KSINV_MINTR_T1FLAIR with {0, 30s, KSINV_MINTR_T1FLAIR, VIS, "Min TR for T1-FLAIR",}

◆ ksinv_maxtr_t1flair

int ksinv_maxtr_t1flair = KSINV_MAXTR_T1FLAIR with {0, 30s, KSINV_MAXTR_T1FLAIR, VIS, "Max TR for T1-FLAIR",}

◆ ksinv_slicecheck

int ksinv_slicecheck = 0 with {0, 1, 0, VIS, "move slice sel to x axis for slice thickness test",}

◆ ksinv_approxti

int ksinv_approxti = 1 with {0, 1, 1, VIS, "allow approx. TI for sliceahead IR mode",}

◆ ksinv_flip

float ksinv_flip = KSINV_DEFAULT_FLIP with {0, 360, KSINV_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}

◆ ksinv_slthickfact

float ksinv_slthickfact = 1.0 with {0, KSINV_MAXTHICKFACT, 1.0, VIS, "Inversion sl.thick / opslthick factor",}

◆ ksinv_rfoffset

int ksinv_rfoffset = 0 with { -10000, 10000, 0, VIS, "RF excitation freq offset [Hz]",}

◆ ksinv_rftype

int ksinv_rftype = KSINV_RF_ADIABATIC with {KSINV_RF_STD, KSINV_RF_ADIABATIC, KSINV_RF_ADIABATIC, VIS, "RF type (0:Std 1:Adiabatic)",}

◆ ksinv_spoilerarea

float ksinv_spoilerarea = KSINV_DEFAULT_SPOILERAREA with {0, 100000, KSINV_DEFAULT_SPOILERAREA, VIS, "Spoiler area",}

◆ ksinv_startpos

int ksinv_startpos = KSINV_DEFAULT_STARTPOS with {16, 10000, KSINV_DEFAULT_STARTPOS, VIS, "Start time of the first grad/RF inversion pulse in sequence module",}

◆ ksinv_t2prep

int ksinv_t2prep = 0 with {0, 1, 0, VIS, "Use T2 preperation instead of conventional Inversion",}

◆ ksinv_t2prep_exc_flip

int ksinv_t2prep_exc_flip = 90 with {0, 180, 90, VIS, "Flip angle of the excitation pulse and the flip down/up pulse for T2 prep",}

◆ ksinv_t2prep_N_Refoc

int ksinv_t2prep_N_Refoc = 1 with {1, 16, 1, VIS, "Number of refocusing pulses in the T2 inversion preperation",}

◆ ksinv_t2prep_TE

int ksinv_t2prep_TE = 100ms with {30ms, 300ms, 100ms, VIS, "TE for T2 inv preperation",}

◆ ksinv_t2prep_rftype_refoc

int ksinv_t2prep_rftype_refoc = KSINV_RF_STD with {KSINV_RF_STD, KSINV_RF_ADIABATIC, KSINV_RF_STD, VIS, "RF type (0:Std 1:Adiabatic)",}

◆ ksinv_slthickfact_exc

float ksinv_slthickfact_exc = 1.0 with {0, KSINV_MAXTHICKFACT, 1.0, VIS, "Inversion sl.thick / opslthick factor",}

◆ Mphysical_inversion

KS_MAT4x4 Mphysical_inversion = KS_MAT4x4_IDENTITY

◆ ksspsat

◆ ksspsat_params

◆ ksspsat_flag

int ksspsat_flag = KSSPSAT_OFF with {KSSPSAT_OFF, KSSPSAT_EXPLICIT, KSSPSAT_OFF, VIS, "flag for ksspsat (0:Off 1:Implicit 2:Explicit)",}

◆ ksspsat_flip

float ksspsat_flip = KSSPSAT_DEFAULT_FLIP with {0, 360, KSSPSAT_DEFAULT_FLIP, VIS, "RF flip angle [deg]",}

◆ ksspsat_rftype

int ksspsat_rftype = KSSPSAT_RF_COMPLEX with {KSSPSAT_RF_STD, KSSPSAT_RF_COMPLEX, KSSPSAT_RF_COMPLEX, VIS, "0: SLR Sat 1: Complex Sat",}

◆ ksspsat_spoilerscale

float ksspsat_spoilerscale = KSSPSAT_DEFAULT_SPOILERSCALE with {0.0, 20.0, KSSPSAT_DEFAULT_SPOILERSCALE, VIS, "scaling of spoiler gradient area",}

◆ ksspsat_spoilallaxes

int ksspsat_spoilallaxes = KSSPSAT_DEFAULT_SPOILALLAXES with {0, 1, KSSPSAT_DEFAULT_SPOILALLAXES, VIS, "apply spoiler on all axes",}

◆ ksspsat_ssi_time

int ksspsat_ssi_time = KSSPSAT_DEFAULT_SSITIME with {10, 20000, KSSPSAT_DEFAULT_SSITIME, VIS, "Time from eos to ssi in intern trig",}

◆ ksspsat_debug

int ksspsat_debug = 0 with {0, 1, 0, VIS, "KSSpSat debug flag",}

◆ ksspsat_oblmethod

int ksspsat_oblmethod = PSD_OBL_RESTRICT with {PSD_OBL_RESTRICT, PSD_OBL_OPTIMAL, PSD_OBL_RESTRICT, VIS, "obl. grad optimization for sat",}