KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
Prep sequence module: Inversion (ksinversion.h)

Data Structures

struct  KSINV_DESIGN
 
struct  KSINV_MODULE
 
struct  KSINV_LOOP_CONTROL_DESIGN
 
struct  KSINV_LOOP_CONTROL
 
struct  KSINV_CHAIN_DESIGN
 
struct  KSINV_MULTI_INV_VOL
 
struct  KSINV_CHAIN
 

Macros

#define KSINV_DEFAULT_FLIP   180
 
#define KSINV_DEFAULT_SPOILERAREA   5000
 
#define KSINV_MINTR_T2FLAIR   8000000
 
#define KSINV_MINTR_T1FLAIR   1400000
 
#define KSINV_MAXTR_T1FLAIR   2800000
 
#define T1_CSF_3T   4400000
 
#define T1_CSF_1_5T   3600000
 
#define T1_GM_3T   1400000
 
#define T1_GM_1_5T   1100000
 
#define T1_WM_3T   750000
 
#define T1_WM_1_5T   600000
 
#define T1_FAT_3T   340000
 
#define T1_FAT_1_5T   260000
 
#define KSINV_SPOILX   1
 
#define KSINV_SPOILY   2
 
#define KSINV_SPOILZ   4
 
#define KSINV_INIT_DESIGN   {"inversion", KS_INIT_SELRF_INVDESIGN, 0, KSINV_GSCALE_NONOVERLAP, 1000.0, KSINV_SPOILX + KSINV_SPOILY + KSINV_SPOILZ, 0, KS_DEFAULT_SSI_TIME}
 
#define KSINV_INIT_MODULE   {KS_INIT_SEQ_CONTROL, KS_INIT_SELRF, KS_INIT_TRAP, KSINV_SPOILX + KSINV_SPOILY + KSINV_SPOILZ, 0}
 
#define KSINV_INIT_LOOP_CONTROL_DESIGN   {KSINV_OFF, KS_NOTSET, KS_NOTSET, FALSE, KS_DEFAULT_SSI_TIME, KSSCAN_INIT_LOOP_CONTROL_DESIGN}
 
#define KSINV_INIT_LOOP_CONTROL   {KSINV_OFF, KS_NOTSET, KS_NOTSET, KS_NOTSET, KS_NOTSET, KS_NOTSET, 0, KSSCAN_INIT_LOOP_CONTROL, KS_INIT_SEQ_CONTROL}
 
#define KSINV_MULTI_INV_MAX_NUM_VOLS   16
 
#define KSINV_INIT_CHAIN_DESIGN   {0, {0}, {KS_INIT_PHASEENCODING_PLAN_DESIGN}, {0}}
 
#define KSINV_INIT_CHAIN   {0, {{0, KS_INIT_PHASEENCODING_PLAN, 0, 0}}}
 

Enumerations

enum  KSINV_MODE { KSINV_OFF, KSINV_ON_INTERLEAVED, KSINV_ON_FLAIR_BLOCK }
 
enum  KSINV_LOOP_MODE { KSINV_LOOP_NORMAL, KSINV_LOOP_SLICEAHEAD_FIRST, KSINV_LOOP_SLICEAHEAD_LAST }
 
enum  KSINV_GSCALE_POLICY { KSINV_GSCALE_SET, KSINV_GSCALE_NONOVERLAP, KSINV_GSCALE_MAXWIDTH }
 

Functions

void ksinv_init_loopcontrol (KSINV_LOOP_CONTROL *loop_control)
 
void ksinv_init_design (KSINV_DESIGN *design, const char *desc)
 
void ksinv_init_sequence (KSINV_MODULE *seq)
 
STATUS ksinv_eval_validatedesign (KSINV_DESIGN *design)
 
STATUS ksinv_eval_setupobjects (KSINV_MODULE *seq, const KSINV_DESIGN *design)
 
STATUS ksinv_pg (KSINV_MODULE *seq)
 
STATUS ksinv_scan_seqstate (KSINV_MODULE *seq, const SCAN_INFO *slice_pos)
 
KS_CORESLICETIME ksinv_scan_irslice (KSINV_MODULE *seq, const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic)
 
float ksinv_eval_gscale (float slice_thickness, float slice_spacing, int numacqs, KSINV_GSCALE_POLICY gscale_policy)
 
STATUS ksinv_eval_design (KSINV_MODULE *invseq, KSINV_DESIGN *invseq_design, int npasses, KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksinv_loop_control_eval_design (KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_SEQ_CONTROL *invseq_seqctrl_ptr, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_SEQ_CONTROL *mainseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design, KS_SEQ_COLLECTION *seqcollection)
 
STATUS ksinv_eval_duration_simple (KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
 
int ksinv_eval_nullti (int TR, int T1value, int seqdur)
 
int ksinv_eval_nulltr (int TI, int T1value, int seqdur)
 
STATUS ksinv_eval_duration_interleaved (KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, KS_SEQ_CONTROL *mainseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
 
STATUS ksinv_eval_duration_flairblock (KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, KS_SEQ_CONTROL *mainseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
 
STATUS ksinv_eval_duration_setfilltr (KS_SEQ_CONTROL *filltr, int duration)
 
STATUS ksinv_check ()
 
STATUS ksinv_predownload_setrecon ()
 
s64 ksinv_scan_sliceloop (KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KSINV_LOOP_MODE ksinv_loop_mode, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksinv_scan_sliceloop_flairblock (KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksinv_scan_sliceloop_sliceahead (KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), int nslicesahead_current, int nslicesahead_next, int play_core)
 
s64 ksinv_scan_acqloop (KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int inv_rampup, const int inv_rampdown)
 
s64 ksinv_scan_scanloop (KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
void ksinv_prescanloop (KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), int nloops, int dda)
 
STATUS ksinv_eval_chain_design (KSINV_CHAIN *inv_chain, KSINV_CHAIN_DESIGN *inv_chain_design, const KSINV_LOOP_CONTROL *inv_loopctrl)
 
s64 ksinv_scan_acqloop_chain (const KSINV_CHAIN *inv_chain, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 
s64 ksinv_scan_scanloop_chain (const KSINV_CHAIN *inv_chain, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
 

Detailed Description

Macro Definition Documentation

◆ KSINV_DEFAULT_FLIP

#define KSINV_DEFAULT_FLIP   180

default inversion flip angle

◆ KSINV_DEFAULT_SPOILERAREA

#define KSINV_DEFAULT_SPOILERAREA   5000

default spoiler area [(G/cm)*us]

◆ KSINV_MINTR_T2FLAIR

#define KSINV_MINTR_T2FLAIR   8000000

default minTR [us] for T2FLAIR, 8 [s]

◆ KSINV_MINTR_T1FLAIR

#define KSINV_MINTR_T1FLAIR   1400000

default minTR [us] for T1FLAIR, 1.4 [s]

◆ KSINV_MAXTR_T1FLAIR

#define KSINV_MAXTR_T1FLAIR   2800000

default maxTR [us] for T1FLAIR, 2.8 [s]

◆ T1_CSF_3T

#define T1_CSF_3T   4400000

Approximate T1 value for CSF at 3T [us]

◆ T1_CSF_1_5T

#define T1_CSF_1_5T   3600000

Approximate T1 value for CSF at 1.5T [us]

◆ T1_GM_3T

#define T1_GM_3T   1400000

Approximate T1 value for gray matter at 3T [us]

◆ T1_GM_1_5T

#define T1_GM_1_5T   1100000

Approximate T1 value for gray matter at 1.5T [us]

◆ T1_WM_3T

#define T1_WM_3T   750000

Approximate T1 value for white matter at 3T [us]

◆ T1_WM_1_5T

#define T1_WM_1_5T   600000

Approximate T1 value for white matter at 1.5T [us]

◆ T1_FAT_3T

#define T1_FAT_3T   340000

Approximate T1 value for fat at 3T [us]

◆ T1_FAT_1_5T

#define T1_FAT_1_5T   260000

Approximate T1 value for fat at 1.5T [us]

◆ KSINV_SPOILX

#define KSINV_SPOILX   1

Bitmask for KSINV_DESIGN spoileraxes to activate spoiling on the logical X-axis

◆ KSINV_SPOILY

#define KSINV_SPOILY   2

Bitmask for KSINV_DESIGN spoileraxes to activate spoiling on the logical Y-axis

◆ KSINV_SPOILZ

#define KSINV_SPOILZ   4

Bitmask for KSINV_DESIGN spoileraxes to activate spoiling on the logical Z-axis

◆ KSINV_INIT_DESIGN

#define KSINV_INIT_DESIGN   {"inversion", KS_INIT_SELRF_INVDESIGN, 0, KSINV_GSCALE_NONOVERLAP, 1000.0, KSINV_SPOILX + KSINV_SPOILY + KSINV_SPOILZ, 0, KS_DEFAULT_SSI_TIME}

Default KSINV_DESIGN values

◆ KSINV_INIT_MODULE

Default values for KSINV_MODULE

◆ KSINV_INIT_LOOP_CONTROL_DESIGN

#define KSINV_INIT_LOOP_CONTROL_DESIGN   {KSINV_OFF, KS_NOTSET, KS_NOTSET, FALSE, KS_DEFAULT_SSI_TIME, KSSCAN_INIT_LOOP_CONTROL_DESIGN}

Default KSINV_LOOP_CONTRO_DESIGN values

◆ KSINV_INIT_LOOP_CONTROL

◆ KSINV_MULTI_INV_MAX_NUM_VOLS

#define KSINV_MULTI_INV_MAX_NUM_VOLS   16

◆ KSINV_INIT_CHAIN_DESIGN

#define KSINV_INIT_CHAIN_DESIGN   {0, {0}, {KS_INIT_PHASEENCODING_PLAN_DESIGN}, {0}}

◆ KSINV_INIT_CHAIN

#define KSINV_INIT_CHAIN   {0, {{0, KS_INIT_PHASEENCODING_PLAN, 0, 0}}}

Enumeration Type Documentation

◆ KSINV_MODE

enum KSINV_MODE
Enumerator
KSINV_OFF 
KSINV_ON_INTERLEAVED 
KSINV_ON_FLAIR_BLOCK 
Definition: ksinversion.h:27
Definition: ksinversion.h:27
Definition: ksinversion.h:27
KSINV_MODE
Definition: ksinversion.h:27

◆ KSINV_LOOP_MODE

Enumerator
KSINV_LOOP_NORMAL 
KSINV_LOOP_SLICEAHEAD_FIRST 
KSINV_LOOP_SLICEAHEAD_LAST 
KSINV_LOOP_MODE
Definition: ksinversion.h:28
Definition: ksinversion.h:28
Definition: ksinversion.h:28
Definition: ksinversion.h:28

◆ KSINV_GSCALE_POLICY

Enumerator
KSINV_GSCALE_SET 
KSINV_GSCALE_NONOVERLAP 
KSINV_GSCALE_MAXWIDTH 
Definition: ksinversion.h:29
KSINV_GSCALE_POLICY
Definition: ksinversion.h:29
Definition: ksinversion.h:29
Definition: ksinversion.h:29

Function Documentation

◆ ksinv_init_loopcontrol()

void ksinv_init_loopcontrol ( KSINV_LOOP_CONTROL loop_control)

Initialize an inversion loop control

Parameters
[out]loop_controlPointer to the inversion loop control to be initialized
Returns
void
193  {
195  *loop_control = loop_init;
196 
197 } /* ksinv_init_loopcontrol() */
#define KSINV_INIT_LOOP_CONTROL
Definition: ksinversion.h:114
Struct holding resulting information controlling all looping in an inversion scan
Definition: ksinversion.h:102

◆ ksinv_init_design()

void ksinv_init_design ( KSINV_DESIGN design,
const char *  desc 
)

Resets the design of the standard inversion module

This function should be called from an sequence (*.e file) that uses ksinversion.h:KSINV_MODULE before setting up its design struct.

Parameters
[out]designPointer to the design struct
[in]descDescription of the sequence
Returns
void
31  {
32  KSINV_DESIGN default_design = KSINV_INIT_DESIGN;
33  *design = default_design;
34 
35  if (desc != NULL && strlen(desc) > 0) {
36  strcpy(design->description, desc);
37  }
38 
39  ks_create_suffixed_description(design->invdesign.description, "%s_selrfinv", design->description);
40 
41 } /* ksinv_init_design() */
void ks_create_suffixed_description(char *const out, const char *const prefix, const char *suffix,...) __attribute__((format(printf
#define KSINV_INIT_DESIGN
Definition: ksinversion.h:67
Design for the standard inversion module
Definition: ksinversion.h:56
KS_DESCRIPTION description
Definition: ksinversion.h:57
KS_SELRF_DESIGN invdesign
Definition: ksinversion.h:58
KS_DESCRIPTION description
Definition: ksdesign.h:49

◆ ksinv_init_sequence()

void ksinv_init_sequence ( KSINV_MODULE seq)

[Internal ksinversion.cc] Resets the KSINV_MODULE struct (arg 1) to KSINV_INIT_MODULE

Parameters
[out]seqPointer to KSINV_MODULE
Returns
void
46  {
47  KSINV_MODULE default_seq = KSINV_INIT_MODULE;
48 
49  *seq = default_seq;
50 
51  /* init seqctrl */
54 
55 } /* ksinv_init_sequence() */
#define KSINV_INIT_MODULE
Definition: ksinversion.h:80
void ks_init_seqcontrol(KS_SEQ_CONTROL *seqcontrol)
Resets KS_SEQ_CONTROL to its default value (KS_INIT_SEQ_CONTROL)
Definition: KSFoundation_host.c:148
Standard inversion module
Definition: ksinversion.h:72
int ssi_time
Definition: KSFoundation.h:1226
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73
#define KS_DEFAULT_SSI_TIME
Definition: KSFoundation.h:207

◆ ksinv_eval_validatedesign()

STATUS ksinv_eval_validatedesign ( KSINV_DESIGN design)

[Internal ksinversion.cc] Checks for limits in the design structures of KSINV_DESIGN

This function is called by ksinv_eval_design() to make sure the user's input design stuctures are valid

Parameters
[in]designKSINV_DESIGN to be validated
Return values
STATUSSUCCESS or FAILURE

◆ ksinv_eval_setupobjects()

STATUS ksinv_eval_setupobjects ( KSINV_MODULE seq,
const KSINV_DESIGN design 
)

[Internal ksinversion.cc] Sets up gradients & RF for the KSINV_MODULE

This function is called by ksinv_eval() to set up the specs (amplitudes and durations) for the sequence objects (gradients, RF, ...) in KSINV_MODULE

Parameters
[out]seqPointer to the inversion module
[in]designPointer to the design struct
Return values
STATUSSUCCESS or FAILURE
103  {
104  STATUS status;
105  KS_DESCRIPTION tmpdesc;
106 
107  /* set up RF excitation */
108  status = ks_eval_design_selrfinv(&seq->selrfinv, design->invdesign);
109  KS_RAISE(status);
110 
111  /* set up spoiler */
112  seq->spoiler.area = design->spoiler_area;
113  ks_create_suffixed_description(tmpdesc, design->description, "_spoiler");
114  /* since minimum IR seq duration is not time critical */
116  KS_RAISE(status);
117 
118  /* Copy fields */
119  seq->spoileraxes = design->spoileraxes;
121  seq->seqctrl.ssi_time = design->ssi_time;
122 
123  return SUCCESS;
124 
125 } /* ksinv_eval_setupobjects() */
STATUS ks_eval_trap_rotation_invariant_75_max_slewrate(KS_TRAP *trap, const char *const desc)
Sets up a trapezoid using a KS_TRAP sequence object with physical gradient constraints (invariant to ...
Definition: KSFoundation_host.c:524
int spoileraxes
Definition: ksinversion.h:76
KS_SELRF selrfinv
Definition: ksinversion.h:74
KS_TRAP spoiler
Definition: ksinversion.h:75
STATUS ks_eval_design_selrfinv(KS_SELRF *selrfinv, const KS_SELRF_DESIGN invdesign)
Function that sets up a KS_SELRF struct for selective RF inversion based on an KS_SELRF_DESIGN
Definition: ksdesign.cc:450
float spoiler_area
Definition: ksinversion.h:61
int spoileraxes
Definition: ksinversion.h:62
int ssi_time
Definition: ksinversion.h:64
void ks_create_suffixed_description(char *const out, const char *const prefix, const char *suffix,...) __attribute__((format(printf
float area
Definition: KSFoundation.h:670
#define KS_RAISE(status)
Definition: KSFoundation.h:190
int ssi_time
Definition: KSFoundation.h:1226
KS_DESCRIPTION description
Definition: ksinversion.h:57
KS_SELRF_DESIGN invdesign
Definition: ksinversion.h:58
int inversion_pulse_shift
Definition: ksinversion.h:63
char KS_DESCRIPTION[KS_DESCRIPTION_LENGTH]
Definition: KSFoundation.h:351
int inversion_pulse_shift
Definition: ksinversion.h:77
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73

◆ ksinv_pg()

STATUS ksinv_pg ( KSINV_MODULE seq)

Generation of the waveforms for the waveform of the standard inversion module

Parameters
[in,out]seqPointer to the inversion module
Return values
STATUSSUCCESS or FAILURE
791  {
792  STATUS status;
793  KS_SEQLOC tmploc = KS_INIT_SEQLOC;
794 
795 #ifdef IPG
796  /* TGT (IPG) only: return early if sequence module duration is zero */
797  if (seq->seqctrl.duration == 0)
798  return SUCCESS;
799 #endif
800 
801  /*******************************************************************************************************
802  * RF Excitation
803  *******************************************************************************************************/
804  tmploc.ampscale = 1.0;
805  tmploc.pos = 16 + RUP_GRD(KS_RFSSP_PRETIME) + seq->inversion_pulse_shift;
806  tmploc.board = ZGRAD;
807 
808  status = ks_pg_selrf(&seq->selrfinv, tmploc, &seq->seqctrl);
809  KS_RAISE(status);
810 
811  /* Save absolute time in sequence for moment start (this is otherwise only done for excitation pulses automatically in ks_pg_selrf() */
812  seq->seqctrl.momentstart = tmploc.pos + seq->selrfinv.grad.ramptime + seq->selrfinv.rf.start2iso;
813 
814 
815  /*******************************************************************************************************
816  * Gradient spoilers on Y and Z (at the same time)
817  *******************************************************************************************************/
818  tmploc.ampscale = 1.0;
819  tmploc.pos += (seq->selrfinv.grad.duration > 0) ? seq->selrfinv.grad.duration : seq->selrfinv.gradwave.duration;
820 
821  if (seq->spoileraxes & KSINV_SPOILX){
822  tmploc.board = XGRAD;
823  status = ks_pg_trap(&seq->spoiler, tmploc, &seq->seqctrl);
824  KS_RAISE(status);
825  }
826 
827  if (seq->spoileraxes & KSINV_SPOILY){
828  tmploc.board = YGRAD;
829  status = ks_pg_trap(&seq->spoiler, tmploc, &seq->seqctrl);
830  KS_RAISE(status);
831  }
832 
833  if (seq->spoileraxes & KSINV_SPOILZ){
834  tmploc.board = ZGRAD;
835  status = ks_pg_trap(&seq->spoiler, tmploc, &seq->seqctrl);
836  KS_RAISE(status);
837  }
838 
839  tmploc.pos += seq->spoiler.duration;
840 
841 
842  /*******************************************************************************************************
843  * Set the minimal sequence duration (seq->seqctrl.min_duration) by calling
844  * ks_eval_seqctrl_setminduration()
845  *******************************************************************************************************/
846 
847 #ifdef HOST_TGT
848  /* On HOST only: Sequence module duration (seq->seqctrl.ssi_time must be > 0 and is added to seq->seqctrl.min_duration in ks_eval_seqctrl_setminduration()) */
849  ks_eval_seqctrl_setminduration(&seq->seqctrl, RUP_GRD(tmploc.pos)); /* tmploc.pos now corresponds to the end of last gradient in the sequence */
850 #endif
851 
852 
853  return SUCCESS;
854 
855 } /* ksinv_pg() */
KS_TRAP grad
Definition: KSFoundation.h:1463
int start2iso
Definition: KSFoundation.h:1032
int pos
Definition: KSFoundation.h:463
int spoileraxes
Definition: ksinversion.h:76
KS_SELRF selrfinv
Definition: ksinversion.h:74
KS_WAVE gradwave
Definition: KSFoundation.h:1465
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:2817
int momentstart
Definition: KSFoundation.h:1228
KS_TRAP spoiler
Definition: ksinversion.h:75
int board
Definition: KSFoundation.h:462
int duration
Definition: KSFoundation.h:1227
float ampscale
Definition: KSFoundation.h:464
#define KSINV_SPOILZ
Definition: ksinversion.h:48
KS_RF rf
Definition: KSFoundation.h:1454
#define KSINV_SPOILY
Definition: ksinversion.h:47
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:1802
#define KS_RAISE(status)
Definition: KSFoundation.h:190
typedef struct used as argument to ks_pg_*** functions to control where and when to place a sequence ...
Definition: KSFoundation.h:461
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:4921
#define KS_INIT_SEQLOC
Definition: KSFoundation.h:287
int duration
Definition: KSFoundation.h:673
int inversion_pulse_shift
Definition: ksinversion.h:77
#define KSINV_SPOILX
Definition: ksinversion.h:46
int ramptime
Definition: KSFoundation.h:671
int duration
Definition: KSFoundation.h:747
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73
#define KS_RFSSP_PRETIME
Definition: KSFoundation.h:217

◆ ksinv_scan_seqstate()

STATUS ksinv_scan_seqstate ( KSINV_MODULE seq,
const SCAN_INFO *  slice_pos 
)

[Internal ksinversion.cc] Sets the current state of a KSINV_MODULE during scanning

This function sets the current state of all ksinv sequence objects being part of KSINV_MODULE, 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]seqPointer to KSINV_MODULE
[in]slice_posPointer to position of the slice to be played out (one element in the ks_scan_info[] array)
Return values
STATUSSUCCESS or FAILURE
860  {
861 
862  if (seq->seqctrl.duration == 0)
863  return SUCCESS;
864 
865  if (slice_info != NULL) {
866 
867  ks_scan_rotate(*slice_info);
868 
869  ks_scan_rf_on(&seq->selrfinv.rf, 0);
870 
872  ks_scan_selrf_setfreqphase_pins(&seq->selrfinv, 0, *slice_info,
874  } else {
875  ks_scan_selrf_setfreqphase(&seq->selrfinv, 0, *slice_info, 0);
876  }
877 
878  } else {
879 
880  ks_scan_rf_off(&seq->selrfinv.rf, 0);
881 
882  }
883 
884  return SUCCESS;
885 
886 } /* 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:566
KS_SELRF selrfinv
Definition: ksinversion.h:74
KS_SMS_INFO sms_info
Definition: KSFoundation.h:1468
float slice_gap
Definition: KSFoundation.h:1337
Definition: KSFoundation.h:2347
int duration
Definition: KSFoundation.h:1227
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:597
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:683
KS_RF rf
Definition: KSFoundation.h:1454
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:606
int mb_factor
Definition: KSFoundation.h:1336
void ks_scan_rotate(SCAN_INFO slice_pos)
Performs a rotation of the logical system on hardware (WARP)
Definition: KSFoundation_tgt.c:1179
int pulse_type
Definition: KSFoundation.h:1338
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73

◆ ksinv_scan_irslice()

KS_CORESLICETIME ksinv_scan_irslice ( KSINV_MODULE seq,
const SCAN_INFO *  slice_pos,
KS_DYNAMIC_STATE *  dynamic 
)

Plays out one inversion slice of the standard inversion module

On TGT on the MR system (PSD_HW), this function sets up (ksinv_scan_seqstate()) and plays out one KSINV_MODULE. 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 only the timing informations are returned. These are used for to compute inversion timing and total scan time.

Parameters
[in]seqPointer to KSINV_MODULE
[in]slice_posPointer to position of the slice to be played out (one element in the ks_scan_info[] array)
[in]dynamicPointer to KS_DYNAMIC_STATE
Return values
KS_CORESLICETIMETime taken in [us] to play out one inversion slice (.duration) and time to center of inversion pulse (.referencetimepoint)
892  {
893  SCAN_INFO slice_pos_updated;
894  int time = 0;
895  float tloc = 0.0;
896  KS_CORESLICETIME coreslicetime = KS_INIT_CORESLICETIME;
897 
898  if (seq == NULL) {
899  return coreslicetime;
900  }
901 
902  if (seq->seqctrl.duration > 0) {
903 
904  if (slice_pos != NULL) {
905  /* TODO: We do have Mlogical too. shall we use it? */
906  ks_scan_update_slice_location(&slice_pos_updated, *slice_pos, dynamic->Mphysical, NULL);
907  tloc = slice_pos_updated.optloc;
908  ksinv_scan_seqstate(seq, &slice_pos_updated);
909  } else {
910  ksinv_scan_seqstate(seq, slice_pos);
911  }
912 
913  /* since the center freq. is changed and multiple slices are imaged with SMS */
914  float sms_slice_positions[seq->selrfinv.sms_info.mb_factor];
915  int slice = 0;
916  for (slice = 0; slice < seq->selrfinv.sms_info.mb_factor; ++slice) {
917  sms_slice_positions[slice] = tloc + seq->selrfinv.sms_info.slice_gap * (0.5 + slice - (seq->selrfinv.sms_info.mb_factor / 2.0));
918  }
919 
920  /* coreslicetime.referencetimepoint assignment must be right *before* ks_scan_playsequence() of the KSINV_MODULE */
921  coreslicetime.referencetimepoint = time + seq->seqctrl.momentstart; /* time from start of the irslice function to the iso point of the inversion pulse */
922  time += ks_scan_playsequence(&seq->seqctrl);
923 
926  sms_slice_positions,
927  seq->selrfinv.slthick,
928  slice_pos == NULL ? KS_PLOT_NO_EXCITATION : KS_PLOT_STANDARD);
929 
930  /* turn on RF again for HTML plotting, so we see the RF even though the slice loop ends with false slices */
931  ks_scan_rf_on(&seq->selrfinv.rf, 0);
932  }
933 
934  /* coreslicetime.duration assignment must be placed at the very end of this function */
935  coreslicetime.duration = time; /* in [us] */
936 
937  return coreslicetime;
938 
939 } /* ksinv_scan_irslice() */
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:566
KS_SELRF selrfinv
Definition: ksinversion.h:74
KS_SMS_INFO sms_info
Definition: KSFoundation.h:1468
float slice_gap
Definition: KSFoundation.h:1337
int momentstart
Definition: KSFoundation.h:1228
Duration and RF center (for excitation or inversion as applicable) of a coreslice/irslice function (h...
Definition: ksscan.h:72
int duration
Definition: KSFoundation.h:1227
int duration
Definition: ksscan.h:73
KS_RF rf
Definition: KSFoundation.h:1454
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1644
Definition: KSFoundation.h:404
Definition: KSFoundation.h:403
int mb_factor
Definition: KSFoundation.h:1336
int referencetimepoint
Definition: ksscan.h:74
#define KS_INIT_CORESLICETIME
Definition: ksscan.h:77
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:4015
void ks_plot_slicetime(const KS_SEQ_CONTROL *ctrl, int nslices, float *slicepos_mm, float slthick_mm, KS_PLOT_EXCITATION_MODE exctype)
ADDTITLEHERE
Definition: KSFoundation_common.c:4276
STATUS ksinv_scan_seqstate(KSINV_MODULE *seq, const SCAN_INFO *slice_info)
[Internal ksinversion.cc] Sets the current state of a KSINV_MODULE during scanning
Definition: ksinversion.cc:860
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73
float slthick
Definition: KSFoundation.h:1456

◆ ksinv_eval_gscale()

float ksinv_eval_gscale ( float  slice_thickness,
float  slice_spacing,
int  numacqs,
KSINV_GSCALE_POLICY  gscale_policy 
)

[Internal ksinversion.cc] Sets up the slice wideing of the inversion

This function is called by ksinv_eval_design() to set seq->design.invdesign.gscale based on other design fields

Parameters
[in]slice_thicknessSlice thickness in [mm]
[in]slice_spacingSlice spacing in [mm]
[in]numacqsNumber of acquistions (passes) for the scan (usually 2+ for inversion sequences)
[in]gscale_policyKSINV_GSCALE_FIXED (uses .gscale), KSINV_GSCALE_NONOVERLAP (IR slices may never overlap regardless of interleaving) or KSINV_GSCALE_MAXWIDTH (IR slice may overlap)
Return values
STATUSSUCCESS or FAILURE
130  {
131  float inv_gscale = 1.0;
132 
133  if (slice_thickness <= 0.0) {
134  return 1.0;
135  }
136 
137  if (slice_spacing < 0.0) {
138  slice_spacing = 0.0;
139  }
140 
141  if (gscale_policy == KSINV_GSCALE_MAXWIDTH) {
142  inv_gscale = 1.0 / ((numacqs * 2.0 * (slice_thickness + slice_spacing) - slice_thickness) / slice_thickness);
143  } else if (gscale_policy == KSINV_GSCALE_NONOVERLAP) {
144  inv_gscale = 1.0 / (numacqs * (slice_thickness + slice_spacing) / slice_thickness);
145  }
146 
147  return inv_gscale;
148 
149 } /* ksinv_eval_gscale() */
Definition: ksinversion.h:29
Definition: ksinversion.h:29

◆ ksinv_eval_design()

STATUS ksinv_eval_design ( KSINV_MODULE invseq,
KSINV_DESIGN invseq_design,
int  npasses,
KS_SEQ_COLLECTION seqcollection 
)

Standard setup function for KSINV_MODULE to be executed on HOST (cveval()) by the parent sequence (*.e)

This function should be called in the cveval() function of a main sequence (*.e) that uses ksinversion.h/ksinversion.cc to generate a standard inversion module.

157  {
158 
159  STATUS s;
160 
161  ksinv_init_sequence(invseq);
162  strncpy(invseq->seqctrl.description, invseq_design->description, KS_DESCRIPTION_LENGTH);
163 
164  /* Inversion slice scale factor based on policy */
165  switch (invseq_design->gscale_policy) {
168  invseq_design->invdesign.gscale = ksinv_eval_gscale(invseq_design->invdesign.slthick,
169  invseq_design->slice_gap,
170  npasses,
171  invseq_design->gscale_policy);
172  break;
173  default:
174  break;
175  }
176 
177  s = ksinv_eval_setupobjects(invseq, invseq_design);
178  KS_RAISE(s);
179 
180  s = ksinv_pg(invseq);
181  KS_RAISE(s);
182 
184  KS_RAISE(s);
185 
186  return SUCCESS;
187 
188 } /* ksinv_eval_design() */
STATUS ksinv_eval_setupobjects(KSINV_MODULE *seq, const KSINV_DESIGN *design)
[Internal ksinversion.cc] Sets up gradients & RF for the KSINV_MODULE
Definition: ksinversion.cc:103
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:207
float gscale
Definition: ksdesign.h:52
void ksinv_init_sequence(KSINV_MODULE *seq)
[Internal ksinversion.cc] Resets the KSINV_MODULE struct (arg 1) to KSINV_INIT_MODULE
Definition: ksinversion.cc:46
#define KS_DESCRIPTION_LENGTH
Definition: KSFoundation.h:253
STATUS ksinv_pg(KSINV_MODULE *seq)
Generation of the waveforms for the waveform of the standard inversion module
Definition: ksinversion.cc:791
Definition: ksinversion.h:29
Definition: ksinversion.h:29
#define KS_RAISE(status)
Definition: KSFoundation.h:190
int slice_gap
Definition: ksinversion.h:59
float ksinv_eval_gscale(float slice_thickness, float slice_spacing, int numacqs, KSINV_GSCALE_POLICY gscale_policy)
[Internal ksinversion.cc] Sets up the slice wideing of the inversion
Definition: ksinversion.cc:130
KS_DESCRIPTION description
Definition: ksinversion.h:57
KS_SELRF_DESIGN invdesign
Definition: ksinversion.h:58
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:82
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
KSINV_GSCALE_POLICY gscale_policy
Definition: ksinversion.h:60
float slthick
Definition: ksdesign.h:50
KS_SEQ_CONTROL seqctrl
Definition: ksinversion.h:73

◆ ksinv_loop_control_eval_design()

STATUS ksinv_loop_control_eval_design ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_SEQ_CONTROL invseq_seqctrl_ptr,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_SEQ_CONTROL mainseq_seqctrl_ptr,
const KSINV_LOOP_CONTROL_DESIGN design,
KS_SEQ_COLLECTION seqcollection 
)

Generate an inversion loop control given both custom core acquisition and inversion

This function is the most general way to generate an inversion loop control. Recall that the objective of an inversion module is to interweave two different blocks of one or more modules (sequence entries). The first block is responsible for sampling the desired k-space data while the second is needed for prepare the magnetization via inversion. Here the two blocks are handled via two function pointer that play a series of modules configured to excite at a specific slice location.

Parameters
[out]inv_loopctrlInversion loop control to be generated
[in]irsliceCoreslice function playing an inversion (and optionally more) modules for a single inversion slice playout
[out]invseq_seqctrl_ptrPointer to the sequence entry among those played in irslice to be inflated if it is needed to fix the timing. Note that it is assumed that this module is played exactly once in irslice.
[in]coreslicePointer to function playing one or more sequence modules for a single playout
[out]mainseq_seqctrl_ptrPointer to the sequence entry among those played in coreslice to be inflated if it is needed to fix the timing. Note that it is assumed that this module is played exactly once in coreslice.
[in]designDesign for the inversion loop control
[in,out]seqcollectionSequence collection to which all modules played in irslice and coreslice ought to have been registered with ks_eval_addtoseqcollection.
Return values
STATUSSUCCESS or FAILURE
208  {
209  STATUS status;
210 
211  ks_init_seqcontrol(&inv_loopctrl->seqctrl_filltr);
212 
213  if (design->irmode == KSINV_OFF || design->loopctrl_design.slicetiming_design.nslices < 1) {
214  ksinv_init_loopcontrol(inv_loopctrl);
215  return SUCCESS;
216  }
217 
218  KS_DYNAMIC_STATE dynamic = KS_INIT_DYNAMIC_STATE;
219  KS_CORESLICETIME irslicetime = irslice(NULL, &dynamic);
220  KS_CORESLICETIME coreslicetime = coreslice(NULL, &dynamic);
221 
222  /* validate design stuct */
223  status = ksinv_validate_loopcontroldesign(design);
224  KS_RAISE(status);
225 
226  /* copy fields */
227  inv_loopctrl->irmode = design->irmode;
228  inv_loopctrl->loopctrl.dda = design->loopctrl_design.dda;
229  inv_loopctrl->loopctrl.nvols = design->loopctrl_design.nvols;
230  inv_loopctrl->loopctrl.naverages = design->loopctrl_design.naverages;
231  inv_loopctrl->loopctrl.play_endofpass = design->loopctrl_design.play_endofpass;
232  inv_loopctrl->seqctrl_filltr.ssi_time = design->filltr_ssi_time;
233 
234  /* generate the phase encoding plan */
236  KS_RAISE(status);
237 
238  /* generate the dummy phase encoding plan */
241  KS_RAISE(status);
242  }
243 
244  /* check against too low maxTR regardless of IR type before continuing */
245  if ((design->loopctrl_design.slicetiming_design.maxTR > 0) && (design->loopctrl_design.slicetiming_design.maxTR < (invseq_seqctrl_ptr->duration + mainseq_seqctrl_ptr->duration))) {
246  return KS_THROW("design.maxTR (%d) too low to fit any slices in", design->loopctrl_design.slicetiming_design.maxTR);
247  }
248 
249  status = ksscan_eval_setup_rf_slices(&inv_loopctrl->loopctrl.slicetiming,
252  KS_RAISE(status);
253 
254  /* Number of slices per TR. May be updated in ksinv_eval_duration_interleaved() */
255  inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass = CEIL_DIV(inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices,
257 
258  if (design->irmode == KSINV_ON_FLAIR_BLOCK) {
259 
260  status = ksinv_eval_duration_flairblock(inv_loopctrl,
261  irslicetime, coreslicetime,
262  invseq_seqctrl_ptr, mainseq_seqctrl_ptr,
263  design);
264  KS_RAISE(status);
265 
266  status = ks_eval_addtoseqcollection(seqcollection, &inv_loopctrl->seqctrl_filltr);
267  KS_RAISE(status);
268 
269  } else if (design->irmode == KSINV_ON_INTERLEAVED) {
270 
271  if (design->T1value != KS_NOTSET) { /* AutoTR in range [.minTR, .maxTR] */
272  status = ksinv_eval_duration_interleaved(inv_loopctrl,
273  irslicetime, coreslicetime,
274  invseq_seqctrl_ptr, mainseq_seqctrl_ptr,
275  design);
276  KS_RAISE(status);
277  } else {
278  status = ksinv_eval_duration_simple(inv_loopctrl,
279  irslicetime, coreslicetime,
280  invseq_seqctrl_ptr,
281  design);
282  KS_RAISE(status);
283  }
284 
285  }
286 
287  /* If SMS, check that nslices_per_pass is an odd number (can some times be helped by adjusting #interleaves) */
288  int inpass_interleaves = design->loopctrl_design.slicetiming_design.inpass_interleaves;
289  status = ks_sms_check_divisibility(&inpass_interleaves,
292  inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices);
293  KS_RAISE(status);
294 
295  /* setup the slice plan for the sequence */
297  inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices,
299  inpass_interleaves);
300 
301 
302  inv_loopctrl->loopctrl.slicetiming.maxslices_per_TR = 2048; /* GEs normal slice max value */
303 
304 
305  return SUCCESS;
306 
307 } /* ksinv_eval_custom() */
STATUS ksscan_phaseencoding_plan_eval_design(KS_PHASEENCODING_PLAN *pe_plan, const KS_PHASEENCODING_PLAN_DESIGN *design)
Generates a phase encodin plan according to design
Definition: ksscan.cc:26
KS_PHASEENCODING_PLAN_DESIGN phaseenc_design_dummies
Definition: ksscan.h:208
KS_KSPACE_ACQ kacq
Definition: ksscan.h:138
KS_PHASEENCODING_PLAN phaseenc_plan_dummies
Definition: ksscan.h:191
int inpass_interleaves
Definition: ksscan.h:27
#define KS_NOTSET
Definition: KSFoundation.h:115
int minacqs
Definition: ksscan.h:26
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
KS_KCOORD * coords
Definition: KSFoundation.h:2228
int naverages
Definition: ksscan.h:204
int irmode
Definition: ksinversion.h:103
int play_endofpass
Definition: ksscan.h:188
STATUS ks_calc_sliceplan_interleaved(KS_SLICE_PLAN *slice_plan, int nslices, int slperpass, int inpass_interleaves)
Calculates the data acquisition order for custom interleaved 2D scans using one or more passes...
Definition: KSFoundation_host.c:6304
Duration and RF center (for excitation or inversion as applicable) of a coreslice/irslice function (h...
Definition: ksscan.h:72
int sms_factor
Definition: ksscan.h:25
KS_PHASEENCODING_PLAN_DESIGN phaseenc_design
Definition: ksscan.h:207
int duration
Definition: KSFoundation.h:1227
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:207
int T1value
Definition: ksinversion.h:91
int nslices_per_pass
Definition: KSFoundation.h:1320
int filltr_ssi_time
Definition: ksinversion.h:93
int dda
Definition: ksscan.h:185
void ks_init_seqcontrol(KS_SEQ_CONTROL *seqcontrol)
Resets KS_SEQ_CONTROL to its default value (KS_INIT_SEQ_CONTROL)
Definition: KSFoundation_host.c:148
int naverages
Definition: ksscan.h:187
int dda
Definition: ksscan.h:202
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
STATUS ksinv_eval_duration_flairblock(KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, KS_SEQ_CONTROL *mainseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
[Internal ksinversion.cc] Sets the sequence module duration of a KSINV_MODULE for a FLAIR block desig...
Definition: ksinversion.cc:554
STATUS ksinv_eval_duration_interleaved(KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, KS_SEQ_CONTROL *mainseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
[Internal ksinversion.cc] Sets the sequence module duration of a KSINV_MODULE as well as TI and TR (s...
Definition: ksinversion.cc:385
Definition: ksinversion.h:27
int nvols
Definition: ksscan.h:203
STATUS ks_sms_check_divisibility(int *inpass_interleaves, const int sms_factor, const int nslices_per_pass, const int nslices)
Checks that nslices_per_pass is an odd number when accelerating with SMS
Definition: KSFoundation_host.c:6438
KS_SLICETIMING_DESIGN slicetiming_design
Definition: ksscan.h:209
int irmode
Definition: ksinversion.h:89
STATUS ksscan_eval_setup_rf_slices(KS_SLICETIMING *slicetiming, const KS_SLICETIMING_DESIGN *slicetiming_design, int is2D)
Setup the slice offsets that will be actually be used
Definition: ksscan.cc:381
int play_endofpass
Definition: ksscan.h:205
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS ksinv_validate_loopcontroldesign(const KSINV_LOOP_CONTROL_DESIGN *design)
Definition: ksinversion.cc:60
Definition: ksinversion.h:27
Definition: ksinversion.h:27
STATUS ksinv_eval_duration_simple(KSINV_LOOP_CONTROL *inv_loopctrl, KS_CORESLICETIME irslicetime, KS_CORESLICETIME coreslicetime, KS_SEQ_CONTROL *invseq_seqctrl_ptr, const KSINV_LOOP_CONTROL_DESIGN *design)
[Internal ksinversion.cc] Sets the inversion timing and slice timing for a simple inversion case with...
Definition: ksinversion.cc:312
int ssi_time
Definition: KSFoundation.h:1226
int nslices
Definition: KSFoundation.h:1318
int maxTR
Definition: ksscan.h:29
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksscan.h:190
void ksinv_init_loopcontrol(KSINV_LOOP_CONTROL *loop_control)
Initialize an inversion loop control
Definition: ksinversion.cc:193
int nslices
Definition: ksscan.h:23
KS_SEQ_COLLECTION seqcollection
Definition: ksepi.e:82
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
int nvols
Definition: ksscan.h:186
int maxslices_per_TR
Definition: ksscan.h:44
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
int is3D
Definition: ksscan.h:24
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
KS_SEQ_CONTROL seqctrl_filltr
Definition: ksinversion.h:111
KSSCAN_LOOP_CONTROL_DESIGN loopctrl_design
Definition: ksinversion.h:94

◆ ksinv_eval_duration_simple()

STATUS ksinv_eval_duration_simple ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_CORESLICETIME  irslicetime,
KS_CORESLICETIME  coreslicetime,
KS_SEQ_CONTROL invseq_seqctrl_ptr,
const KSINV_LOOP_CONTROL_DESIGN design 
)

[Internal ksinversion.cc] Sets the inversion timing and slice timing for a simple inversion case with fixed TI (.T1value = KS_NOTSET)

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), coreslicetime.referencetimepoint 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 coreslicetime.referencetimepoint 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 .design.TI is short in relation to coreslicetime.referencetimepoint this function will return an error.

If design->dosliceahead > 0, then the inversion duration is attempted to be reduced by playing the IR module in a slice-ahead fashion (like T1-FLAIR). Even for STIR sequences (depending on the ETL of the main sequence) it can be possible to get very low time penalty with the IR pulse, provided that the main sequence can fit in the dead space of the inversion duration.

Parameters
[out]inv_loopctrlPointer to the inversion loop control to be generated
[in]irslicetimeKS_CORESLICETIME returned by the irslice function (usually ksinv_scan_irslice())
[in]coreslicetimeKS_CORESLICETIME returned by the coreslice function of the main sequence (cf. ksfse.cc:ksfse_scan_coreslice(), ksepi.cc:ksepi_scan_coreslice())
[in,out]invseq_seqctrl_ptrPointer to KS_SEQ_CONTROL of the inversion sequence to be used. Note that the duration might be altered to adjust the timing
[in]designPointer to inverion loop control design
Return values
STATUSSUCCESS or FAILURE
314  {
315 
316  if (design->irmode != KSINV_ON_INTERLEAVED) {
317  return KS_THROW("design.irmode must be KSINV_ON_INTERLEAVED for this function");
318  }
319  if (design->TI <= 5000) {
320  return KS_THROW("design.TI must be > 5 ms");
321  }
322  if (design->T1value != KS_NOTSET) {
323  return KS_THROW("AutoTI not supported .design.T1value must be KS_NOTSET (-1)");
324  }
325  if (irslicetime.referencetimepoint < 0 || irslicetime.duration <= 0) {
326  return KS_THROW("irslicetime field .referencetimepoint and .duration must be > 0");
327  }
328  if (coreslicetime.referencetimepoint < 0 || coreslicetime.duration <= 0) {
329  return KS_THROW("corslicetime field .referencetimepoint and .duration must be > 0");
330  }
331 
332  /* Initialize with no sliceahead */
333  inv_loopctrl->nslicesahead = 0;
334 
335  int inversiongap = RUP_GRD(design->TI - coreslicetime.referencetimepoint + irslicetime.referencetimepoint - irslicetime.duration);
336  if (inversiongap < 0) {
337  return KS_THROW("TI = %d resulted in a too short inv. seq. duration", design->TI/1000);
338  }
339 
340  if (design->dosliceahead && inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass > 1 &&
341  inversiongap > (irslicetime.duration + coreslicetime.duration)) {
342 
343  inv_loopctrl->nslicesahead = inversiongap / (irslicetime.duration + coreslicetime.duration);
344  if (inv_loopctrl->nslicesahead > inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass - 1) {
345  inv_loopctrl->nslicesahead = inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass - 1; /* Don't exceed #slices per pass - 1 */
346  }
347  int timeleft = inversiongap - (inv_loopctrl->nslicesahead * (irslicetime.duration + coreslicetime.duration));
348  irslicetime.duration += RUP_GRD(timeleft / (inv_loopctrl->nslicesahead + 1));
349  } else {
350  irslicetime.duration += inversiongap;
351  }
352 
353  /* TI & TR states. Adjust duration of IR sequence (played in irslice) and main sequence (played in coreslice) */
354  inv_loopctrl->TI = design->TI;
355  inv_loopctrl->loopctrl.slicetiming.TR = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass;
356  if (irslicetime.duration > invseq_seqctrl_ptr->duration) {
357  invseq_seqctrl_ptr->duration = RUP_GRD(irslicetime.duration);
358  }
359 
360  return SUCCESS;
361 
362 } /* ksinv_eval_duration_simple() */
#define KS_NOTSET
Definition: KSFoundation.h:115
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int duration
Definition: KSFoundation.h:1227
int T1value
Definition: ksinversion.h:91
int TI
Definition: ksinversion.h:104
int duration
Definition: ksscan.h:73
int nslices_per_pass
Definition: KSFoundation.h:1320
int TR
Definition: ksscan.h:43
int irmode
Definition: ksinversion.h:89
Definition: ksinversion.h:27
int referencetimepoint
Definition: ksscan.h:74
int TI
Definition: ksinversion.h:90
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int nslicesahead
Definition: ksinversion.h:106
int dosliceahead
Definition: ksinversion.h:92

◆ ksinv_eval_nullti()

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

[Internal ksinversion.cc] 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]
Returns
TItime Inversion time in [us]
367  {
368 
369  return (int) ((double) T1value * ( log(2.0) - log(1.0 + exp(-((double) TR - (double) seqdur)/((double) T1value))) ));
370 
371 } /* ksinv_eval_nullti() */

◆ ksinv_eval_nulltr()

int ksinv_eval_nulltr ( int  TI,
int  T1value,
int  seqdur 
)

[Internal ksinversion.cc (currently not used)] Calculates the TR value corresponding to a given T1 value,

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

Parameters
[in]TIInversion time in [us]
[in]T1valueThe T1 value of the tissue to be nulled in [us]
[in]seqdurThe duration of the main sequence in [us]
Returns
TR Repetition time in [us]
376  {
377 
378  return (int) ((double) -T1value * log(2.0 * exp(-((double) TI)/((double) T1value)) - 1.0) + seqdur);
379 
380 } /* ksinv_eval_nulltr() */

◆ ksinv_eval_duration_interleaved()

STATUS ksinv_eval_duration_interleaved ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_CORESLICETIME  irslicetime,
KS_CORESLICETIME  coreslicetime,
KS_SEQ_CONTROL invseq_seqctrl_ptr,
KS_SEQ_CONTROL mainseq_seqctrl_ptr,
const KSINV_LOOP_CONTROL_DESIGN design 
)

[Internal ksinversion.cc] Sets the sequence module duration of a KSINV_MODULE as well as TI and TR (slice-ahead IR) for a T1-FLAIR type of scan

This function will set up the TI and TR (within seq.slicetiming.design.minTR/maxTR) and set the .seqctrl.duration for both the inversion and main sequence accordingly. It is a requirement for this function to work with AutoTR (some range given bydesign.minTR/maxTR differences) and AutoTI (.T1value > 0 and .TI = KS_NOTSET).

The inversion time will be approximated by the number of slices that can be played slice-aheaed but efforts are made to shift time between the inversion and main sequence to come as close to the optimal TI as possible. This is easier for main sequences with short ETL, many slices and long T1values (CSF), which is the typical case for T1-FLAIR.

This function will be used for STIR cases (with short TI) when AutoTI (.T1value > 0 and .TI = KS_NOTSET) in ksinv_eval() is selecting this function over ksinv_eval_duration_simple().

Parameters
[in,out]inv_loopctrlPointer to the inversion loop control
[in]irslicetimeKS_CORESLICETIME returned by the irslice function (usually ksinv_scan_irslice())
[in]coreslicetimeKS_CORESLICETIME returned by the coreslice function of the main sequence (cf. ksfse.cc:ksfse_scan_coreslice(), ksepi.cc:ksepi_scan_coreslice())
[in]invseq_seqctrl_ptrPointer to the inversion sequence control to be used
[in]mainseq_seqctrl_ptrPointer to the main sequence control to be used
[in]designPointer to inverion loop control design
Return values
STATUSSUCCESS or FAILURE
388  {
389 
390  if (design->irmode != KSINV_ON_INTERLEAVED) {
391  return KS_THROW("design.irmode must be KSINV_ON_INTERLEAVED for this function");
392  }
393 
394  if (design->TI != KS_NOTSET) {
395  return KS_THROW("design.TI must be KS_NOTSET (-1)");
396  }
397  if (design->T1value <= 5000) {
398  return KS_THROW("AutoTI required .design.T1value must be > 5ms");
399  }
400  if (coreslicetime.referencetimepoint == KS_NOTSET || coreslicetime.duration == KS_NOTSET) {
401  return KS_THROW("Passed coreslice must have .referencetimepoint > 0 and .duration > 0");
402  }
403  if (irslicetime.referencetimepoint == KS_NOTSET || irslicetime.duration == KS_NOTSET) {
404  return KS_THROW("Passed irslice must have .referencetimepoint > 0 and .duration > 0");
405  }
406 
407  int TR, max_nslicesahead;
408  int approxTI, TI, TIdiff, TRsum;
409  int numacqs_needed = KS_NOTSET;
410  const KS_CORESLICETIME irslicetime_orig = irslicetime;
411  const KS_CORESLICETIME coreslicetime_orig = coreslicetime;
412  const int shrinklimit_mainseq = mainseq_seqctrl_ptr->duration - mainseq_seqctrl_ptr->min_duration;
413  const int shrinklimit_irseq = invseq_seqctrl_ptr->duration - invseq_seqctrl_ptr->min_duration;
414 
415  if (design->loopctrl_design.slicetiming_design.nslices < 1) {
416  return KS_THROW("nslices must be positive");
417  }
418 
419 
420  /* Step 1 - Find out how many acqs we need to not exceed design->loopctrl_design.slicetiming_design.maxTR (for approxTI = 0, we need one more IR+main as margin) */
421  if (design->loopctrl_design.slicetiming_design.maxTR > 0) { /* maxTR is limited */
422 
423  /* sum or TRs for all slices */
424  TRsum = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices;
425 
426  /* Number of acqs (passes) needed to keep TR below .maxTR */
427  numacqs_needed = IMax(2, CEIL_DIV(TRsum, design->loopctrl_design.slicetiming_design.maxTR), design->loopctrl_design.slicetiming_design.minacqs);
428 
429  /* Number of slices that fit within the valid TR (< .maxTR) */
430  inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass = CEIL_DIV(inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices, numacqs_needed);
431 
432  } else { /* TR has no upper limit */
433 
435 
436  }
437 
438 
439  /* Step 2 - Inflate the duration of the main sequence *if* the number of slices don't reach up to .design.minTR */
440  TR = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass;
441  if (TR < design->loopctrl_design.slicetiming_design.minTR) {
442  int timetoadd_perTR = (design->loopctrl_design.slicetiming_design.minTR - TR);
443  coreslicetime.duration += RUP_GRD(CEIL_DIV(timetoadd_perTR, inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass));
444  TR = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass;
445  }
446  TI = ksinv_eval_nullti(TR, design->T1value, mainseq_seqctrl_ptr->min_duration);
447 
448  int inversiongap = RDN_GRD(TI - coreslicetime.referencetimepoint + irslicetime.referencetimepoint - irslicetime.duration);
449  if (inversiongap < 0) {
450  return KS_THROW("TI = %d resulted in a too short inv. seq. duration", TI/1000);
451  }
452 
453 
454  /* Step 3 - # slices that the IR sequence should be (temporally) ahead of the main sequence (to effectively create all/most of the TI time) */
455  max_nslicesahead = inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass - 1;
456  if (design->dosliceahead) {
457  inv_loopctrl->nslicesahead = inversiongap / (irslicetime.duration + coreslicetime.duration);
458  if (inv_loopctrl->nslicesahead > max_nslicesahead) {
459  inv_loopctrl->nslicesahead = max_nslicesahead;
460  }
461  if (inv_loopctrl->nslicesahead < 0) {
462  inv_loopctrl->nslicesahead = 0;
463  }
464  } else {
465  inv_loopctrl->nslicesahead = 0;
466  }
467 
468 
469  /* Step 4 - Approximate TI */
470  int shrinklimit_coreslice = 0;
471  int shrinklimit_irslice = 0;
472  int irslicetime_temp_duration[2];
473  int coreslice_temp_duration[2];
474  int napprox_directions = (inv_loopctrl->nslicesahead < max_nslicesahead) ? 2 : 1; /* if we can add one more sliceahead, then try also to round up TI */
475  int adjust_amount[2] = {0, 0};
476  int approx_dir;
477  double errTI[2];
478 
479 
480  for (approx_dir = 0; approx_dir < napprox_directions; approx_dir++) {
481  /* 0: approx down 1: approx up */
482 
483  TR = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass;
484  TI = ksinv_eval_nullti(TR, design->T1value, mainseq_seqctrl_ptr->min_duration);
485 
486  approxTI = (inv_loopctrl->nslicesahead + approx_dir) * (irslicetime.duration + coreslicetime.duration) + irslicetime.duration - irslicetime.referencetimepoint + coreslicetime.referencetimepoint;
487 
488  if (approx_dir == 0) {
489  TIdiff = TI - approxTI;
490  } else {
491  TIdiff = approxTI - TI;
492  }
493 
494  if (TIdiff < 0) {
495  return KS_THROW("APPROX TI PROGRAMMING ERROR");
496  }
497 
498  if (approx_dir == 0) {
499  /* move time from coreslice to irslice. This increases approxTI by 'adjust_amount' with TR unchanged, hence previous target 'TI' is still valid */
500 
501  shrinklimit_coreslice = shrinklimit_mainseq + (coreslicetime.duration - coreslicetime_orig.duration);
502  adjust_amount[approx_dir] = IMin(2, shrinklimit_coreslice, TIdiff);
503 
504  coreslice_temp_duration[approx_dir] = coreslicetime.duration - RUP_GRD(adjust_amount[approx_dir]);
505  irslicetime_temp_duration[approx_dir] = irslicetime.duration + RUP_GRD(adjust_amount[approx_dir]);
506  } else {
507  /* move time from irslice to coreslice. This decreases approxTI by 'adjust_amount' with TR unchanged, hence previous target 'TI' is still valid */
508 
509  shrinklimit_irslice = shrinklimit_irseq + (irslicetime.duration - irslicetime_orig.duration);
510  adjust_amount[approx_dir] = IMin(2, shrinklimit_irslice, TIdiff);
511 
512  coreslice_temp_duration[approx_dir] = coreslicetime.duration + RUP_GRD(adjust_amount[approx_dir]);
513  irslicetime_temp_duration[approx_dir] = irslicetime.duration - RUP_GRD(adjust_amount[approx_dir]);
514  }
515 
516  approxTI = (inv_loopctrl->nslicesahead + approx_dir) * (irslicetime_temp_duration[approx_dir] + coreslice_temp_duration[approx_dir]) + irslicetime_temp_duration[approx_dir] - irslicetime.referencetimepoint + coreslicetime.referencetimepoint;
517 
518  errTI[approx_dir] = fabs(((double) TI - (double) approxTI) / (double) TI);
519 
520  } /* approx up or down */
521 
522 
523  if ((errTI[0] < errTI[1]) || (napprox_directions == 1)) {
524  irslicetime.duration += adjust_amount[0];
525  coreslicetime.duration -= adjust_amount[0];
526  } else {
527  inv_loopctrl->nslicesahead++;
528  irslicetime.duration -= adjust_amount[1];
529  coreslicetime.duration += adjust_amount[1];
530  }
531 
532 
533  /* Update TI & TR again after duration changes */
534  TR = (irslicetime.duration + coreslicetime.duration) * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass;
535  TI = ksinv_eval_nullti(TR, design->T1value, mainseq_seqctrl_ptr->min_duration);
536  approxTI = (inv_loopctrl->nslicesahead) * (irslicetime.duration + coreslicetime.duration) + irslicetime.duration - irslicetime.referencetimepoint + coreslicetime.referencetimepoint;
537 
538  /* TI & TR states. Adjust duration of IR sequence (played in irslice) and main sequence (played in coreslice) */
539  inv_loopctrl->TI = approxTI;
540  inv_loopctrl->errorTI = approxTI - TI;
541  inv_loopctrl->loopctrl.slicetiming.TR = TR;
542  invseq_seqctrl_ptr->duration += RUP_GRD(irslicetime.duration - irslicetime_orig.duration);
543  mainseq_seqctrl_ptr->duration += RUP_GRD(coreslicetime.duration - coreslicetime_orig.duration);
544 
545 
546  return SUCCESS;
547 
548 
549 } /* ksinv_eval_duration_interleaved() */
#define KS_NOTSET
Definition: KSFoundation.h:115
int minacqs
Definition: ksscan.h:26
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int errorTI
Definition: ksinversion.h:105
Duration and RF center (for excitation or inversion as applicable) of a coreslice/irslice function (h...
Definition: ksscan.h:72
int duration
Definition: KSFoundation.h:1227
int T1value
Definition: ksinversion.h:91
int TI
Definition: ksinversion.h:104
int ksinv_eval_nullti(int TR, int T1value, int seqdur)
[Internal ksinversion.cc] Calculates the TI value necessary to null the signal from a tissue with a g...
Definition: ksinversion.cc:367
int duration
Definition: ksscan.h:73
int nslices_per_pass
Definition: KSFoundation.h:1320
int TR
Definition: ksscan.h:43
int min_duration
Definition: KSFoundation.h:1224
KS_SLICETIMING_DESIGN slicetiming_design
Definition: ksscan.h:209
int irmode
Definition: ksinversion.h:89
Definition: ksinversion.h:27
int referencetimepoint
Definition: ksscan.h:74
int TI
Definition: ksinversion.h:90
int nslices
Definition: KSFoundation.h:1318
int maxTR
Definition: ksscan.h:29
int nslices
Definition: ksscan.h:23
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int minTR
Definition: ksscan.h:28
KSSCAN_LOOP_CONTROL_DESIGN loopctrl_design
Definition: ksinversion.h:94
int nslicesahead
Definition: ksinversion.h:106
int dosliceahead
Definition: ksinversion.h:92

◆ ksinv_eval_duration_flairblock()

STATUS ksinv_eval_duration_flairblock ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_CORESLICETIME  irslicetime,
KS_CORESLICETIME  coreslicetime,
KS_SEQ_CONTROL invseq_seqctrl_ptr,
KS_SEQ_CONTROL mainseq_seqctrl_ptr,
const KSINV_LOOP_CONTROL_DESIGN design 
)

[Internal ksinversion.cc] Sets the sequence module duration of a KSINV_MODULE for a FLAIR block design

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

For few slices, the TR is increased by a separate empty pulse sequnce (seq.seqctrl_filltr) to reach slicetiming.design.minTR.

Parameters
[in,out]inv_loopctrlPointer to the inversion loop control
[in]irslicetimeKS_CORESLICETIME returned by the irslice function (usually ksinv_scan_irslice())
[in]coreslicetimeKS_CORESLICETIME returned by the coreslice function of the main sequence (cf. ksfse.cc:ksfse_scan_coreslice(), ksepi.cc:ksepi_scan_coreslice())
[in]invseq_seqctrl_ptrPointer to the inversion sequence control to be used
[in]mainseq_seqctrl_ptrPointer to the main sequence control to be used
[in]designPointer to inverion loop control design
Return values
STATUSSUCCESS or FAILURE
557  {
558  STATUS status;
559 
560  if (design->irmode != KSINV_ON_FLAIR_BLOCK) {
561  return KS_THROW("design.irmode must be KSINV_ON_FLAIR_BLOCK for this function");
562  }
563  if (invseq_seqctrl_ptr->min_duration <= 0) {
564  return KS_THROW("min_duration of the inversion sequence (arg 1) must be > 0");
565  }
566  if (mainseq_seqctrl_ptr->min_duration <= 0) {
567  return KS_THROW("min_duration of the main sequence must be > 0");
568  }
569  if (mainseq_seqctrl_ptr->duration < mainseq_seqctrl_ptr->min_duration) {
570  return KS_THROW("main sequence's duration of the main sequence must be > %d us", mainseq_seqctrl_ptr->min_duration);
571  }
572  if (invseq_seqctrl_ptr->duration < invseq_seqctrl_ptr->min_duration) {
573  return KS_THROW("inversion sequence's duration of the main sequence must be > %d us", invseq_seqctrl_ptr->min_duration);
574  }
575  if (design->dosliceahead) {
576  return KS_THROW("dosliceahead must be 0");
577  } else {
578  inv_loopctrl->nslicesahead = 0;
579  }
580  if (design->TI != KS_NOTSET && design->TI <= 10000) {
581  return KS_THROW("TI must be > 10 ms");
582  }
583  if (design->T1value > 0 && design->T1value <= 10000) {
584  return KS_THROW("T1value must be > 10 ms");
585  }
586  if (coreslicetime.referencetimepoint == KS_NOTSET || coreslicetime.duration == KS_NOTSET) {
587  return KS_THROW("Passed coreslice must have .referencetimepoint > 0 and .duration > 0");
588  }
589  if (irslicetime.referencetimepoint == KS_NOTSET || irslicetime.duration == KS_NOTSET) {
590  return KS_THROW("Passed irslice must have .referencetimepoint > 0 and .duration > 0");
591  }
592 
593  int avail_flairseqtime;
594  int lastTR = KS_NOTSET;
595  int TR = KS_NOTSET;
596  int TI = KS_NOTSET;
597  int timetoadd_perTR;
598  const float TRtol = 0.01;
599  const int itermax = 20;
600  int iter = 0;
601  const KS_CORESLICETIME irslicetime_orig = irslicetime;
602  const KS_CORESLICETIME coreslicetime_orig = coreslicetime;
603  const int shrinklimit_mainseq = mainseq_seqctrl_ptr->duration - mainseq_seqctrl_ptr->min_duration;
604 
605  if (design->loopctrl_design.slicetiming_design.nslices < 1) {
606  return KS_THROW("nslices must be positive");
607  }
608 
609  inv_loopctrl->seqctrl_filltr.duration = 0;
610  TR = 20000000; /* 20 s to start with */
611 
612  for (iter = 0; iter < itermax; iter++) {
613 
614  coreslicetime.duration = IMax(2, coreslicetime_orig.duration, irslicetime_orig.duration); /* Blocks must be equal to max of them for FLAIR */
615  irslicetime.duration = coreslicetime.duration;
616 
617  /* Step 1 - Get the minimum possible TR (incl SAR/heating and design.minTR) and the resulting TI */
618  if (design->T1value > 0) {
619  /* autoTI */
620  TI = ksinv_eval_nullti(IMax(2, TR, design->loopctrl_design.slicetiming_design.minTR), design->T1value, mainseq_seqctrl_ptr->min_duration);
621  } else {
622  TI = design->TI;
623  }
624 
625 
626  /* Step 2 - Get the number of FLAIR slices per block and number of blocks */
627  avail_flairseqtime = irslicetime.referencetimepoint + TI - coreslicetime.referencetimepoint;
628  if (avail_flairseqtime < 0) {
629  return KS_THROW("TI too short to allow inversion");
630  }
631  inv_loopctrl->nflairslices = avail_flairseqtime / coreslicetime.duration; /* how many slices that can be fitted within 'TI' */
632  if (inv_loopctrl->nflairslices == 0) {
633  /* round-up (fall back to simple IR style). We have already checked that TI is long enough to fit one IR playout */
634  inv_loopctrl->nflairslices = 1;
635  }
636  if (inv_loopctrl->nflairslices > inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass) {
637  inv_loopctrl->nflairslices = inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass; /* don't exceed the total number of slices per pass */
638  }
639  inv_loopctrl->nflairslices -= inv_loopctrl->nflairslices % design->loopctrl_design.slicetiming_design.sms_factor; /* SMS compatibility (mb_factor = 1 for non-SMS) */
640  inv_loopctrl->nflairblocks = CEIL_DIV(inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass, inv_loopctrl->nflairslices); /* number of FLAIR blocks needed to play inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass slices */
641 
642 
643  /* Step 3 - Adjust the IR seq duration and main sequence, then get new actual TR */
644  irslicetime.duration = RUP_GRD(avail_flairseqtime / inv_loopctrl->nflairslices);
645  if (irslicetime.duration < (coreslicetime_orig.duration - shrinklimit_mainseq) && inv_loopctrl->nflairslices > 1) {
646  return KS_THROW("FLAIR slice duration became shorter than shortest possible coreslice duration");
647  } else {
648  coreslicetime.duration = irslicetime.duration;
649  }
650  TR = (irslicetime.duration * inv_loopctrl->nflairslices * inv_loopctrl->nflairblocks) + (coreslicetime.duration * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass); /* without seqctrl_filltr this time */
651 
652 
653  /* Step 4 - If TR < design->loopctrl_design.slicetiming_design.minTR, add this duration to the fillTR sequence module */
654  if (TR < design->loopctrl_design.slicetiming_design.minTR) {
655  timetoadd_perTR = design->loopctrl_design.slicetiming_design.minTR - TR;
656  status = ksinv_eval_duration_setfilltr(&inv_loopctrl->seqctrl_filltr, RUP_GRD(timetoadd_perTR / inv_loopctrl->nflairblocks));
657  } else {
658  status = ksinv_eval_duration_setfilltr(&inv_loopctrl->seqctrl_filltr, 0);
659  }
660  KS_RAISE(status);
661 
662 
663  TR = (irslicetime.duration * inv_loopctrl->nflairslices * inv_loopctrl->nflairblocks) + (coreslicetime.duration * inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass) + inv_loopctrl->seqctrl_filltr.duration;
664 
665  if (((float) abs(lastTR - TR) / (float) TR) < TRtol) {
666  break;
667  } else {
668  lastTR = TR;
669  }
670 
671  } /* for iter */
672 
673 
674 
675  /* TI & TR states. Adjust duration of IR sequence (played in irslice) and main sequence (played in coreslice) */
676  inv_loopctrl->TI = TI;
677  inv_loopctrl->loopctrl.slicetiming.TR = TR;
678  invseq_seqctrl_ptr->duration += RUP_GRD(irslicetime.duration - irslicetime_orig.duration);
679  mainseq_seqctrl_ptr->duration += RUP_GRD(coreslicetime.duration - coreslicetime_orig.duration);
680 
681  return SUCCESS;
682 
683 } /* ksinv_eval_duration_flairblock() */
#define KS_NOTSET
Definition: KSFoundation.h:115
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int nflairslices
Definition: ksinversion.h:107
STATUS ksinv_eval_duration_setfilltr(KS_SEQ_CONTROL *filltr, int duration)
[Internal ksinversion.cc] Creates an empty sequence for the purpose of reaching up to TR for FLAIR bl...
Definition: ksinversion.cc:688
Duration and RF center (for excitation or inversion as applicable) of a coreslice/irslice function (h...
Definition: ksscan.h:72
int sms_factor
Definition: ksscan.h:25
int duration
Definition: KSFoundation.h:1227
int T1value
Definition: ksinversion.h:91
int TI
Definition: ksinversion.h:104
int nflairblocks
Definition: ksinversion.h:108
int ksinv_eval_nullti(int TR, int T1value, int seqdur)
[Internal ksinversion.cc] Calculates the TI value necessary to null the signal from a tissue with a g...
Definition: ksinversion.cc:367
int duration
Definition: ksscan.h:73
int nslices_per_pass
Definition: KSFoundation.h:1320
int TR
Definition: ksscan.h:43
int min_duration
Definition: KSFoundation.h:1224
KS_SLICETIMING_DESIGN slicetiming_design
Definition: ksscan.h:209
int irmode
Definition: ksinversion.h:89
#define KS_RAISE(status)
Definition: KSFoundation.h:190
Definition: ksinversion.h:27
int referencetimepoint
Definition: ksscan.h:74
int TI
Definition: ksinversion.h:90
int nslices
Definition: ksscan.h:23
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int minTR
Definition: ksscan.h:28
KS_SEQ_CONTROL seqctrl_filltr
Definition: ksinversion.h:111
KSSCAN_LOOP_CONTROL_DESIGN loopctrl_design
Definition: ksinversion.h:94
int nslicesahead
Definition: ksinversion.h:106
int dosliceahead
Definition: ksinversion.h:92

◆ ksinv_eval_duration_setfilltr()

STATUS ksinv_eval_duration_setfilltr ( KS_SEQ_CONTROL filltr,
int  duration 
)

[Internal ksinversion.cc] Creates an empty sequence for the purpose of reaching up to TR for FLAIR block inversion

Parameters
[in,out]filltrPointer to KS_SEQ_CONTROL for the empty sequence
[in]durationDuration in [us] for the empty fill sequence
Return values
STATUSSUCCESS or FAILURE
688  {
689 
690  if (filltr->ssi_time <= 0) {
691  return KS_THROW("filltr.ssi_time must be positive");
692  }
693 
694  if (duration >= filltr->ssi_time) {
695  sprintf(filltr->description, "filltr");
696  filltr->min_duration = RUP_GRD(filltr->ssi_time);
697  filltr->duration = RUP_GRD(duration);
698  } else {
699  ks_init_seqcontrol(filltr);
700  sprintf(filltr->description, "filltr_disabled");
701  }
702 
703  return SUCCESS;
704 
705 } /* ksinv_eval_duration_setfilltr() */
int duration
Definition: KSFoundation.h:1227
void ks_init_seqcontrol(KS_SEQ_CONTROL *seqcontrol)
Resets KS_SEQ_CONTROL to its default value (KS_INIT_SEQ_CONTROL)
Definition: KSFoundation_host.c:148
int min_duration
Definition: KSFoundation.h:1224
int ssi_time
Definition: KSFoundation.h:1226
KS_DESCRIPTION description
Definition: KSFoundation.h:1234
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksinv_check()

STATUS ksinv_check ( )

Checks related to inversion

Return values
STATUSSUCCESS or FAILURE
710  {
711 
712  return SUCCESS;
713 
714 } /* ksinv_check() */

◆ ksinv_predownload_setrecon()

STATUS ksinv_predownload_setrecon ( )

Sets IR-related recon variables in predownload

Return values
STATUSSUCCESS or FAILURE
719  {
720 
721  return SUCCESS;
722 
723 } /* ksinv_predownload_setrecon() */

◆ ksinv_scan_sliceloop()

s64 ksinv_scan_sliceloop ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KSINV_LOOP_MODE  ksinv_loop_mode,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

Plays a single repetition of an inversion sequence

Parameters
[in]inv_loopctrlInversion loop control that describe the looping patterns
[in,out]dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions and which is ultimately used to set the state for all modules
[in]ksinv_loop_modeType of TR to played if the inversions are interleaved (irmode = KSINV_ON_INTERLEAVED)
[in]coreslicePointer to function playing one or more sequence modules for a single playout
[in]irslicePointer to function playing an inversion (and optionally more) modules for a single inversion slice playout
Return values
timeDuration in [us] to play out the scope of the function in real time
948  {
949  if (inv_loopctrl->irmode == KSINV_ON_FLAIR_BLOCK) {
950  return ksinv_scan_sliceloop_flairblock(inv_loopctrl,
951  dynamic,
952  coreslice,
953  irslice);
954  }
955 
956  const int nslicesahead_current = ksinv_loop_mode == KSINV_LOOP_SLICEAHEAD_FIRST ?
957  KS_NOTSET : inv_loopctrl->nslicesahead;
958  const int nslicesahead_next = ksinv_loop_mode == KSINV_LOOP_SLICEAHEAD_LAST ?
959  KS_NOTSET : inv_loopctrl->nslicesahead;
960  const int play_core = ksinv_loop_mode != KSINV_LOOP_SLICEAHEAD_FIRST;
961 
962  return ksinv_scan_sliceloop_sliceahead(inv_loopctrl,
963  dynamic,
964  coreslice,
965  irslice,
966  nslicesahead_current,
967  nslicesahead_next,
968  play_core);
969 
970 } /* ksinv_scan_sliceloop() */
#define KS_NOTSET
Definition: KSFoundation.h:115
int irmode
Definition: ksinversion.h:103
s64 ksinv_scan_sliceloop_flairblock(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
[Internal ksinversion.cc] Plays out one repetition for an inversion scan
Definition: ksinversion.cc:1095
Definition: ksinversion.h:28
Definition: ksinversion.h:28
Definition: ksinversion.h:27
s64 ksinv_scan_sliceloop_sliceahead(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int nslicesahead_current, const int nslicesahead_next, const int play_core)
[Internal ksinversion.cc] Plays a single repetition of an interleaved inversion sequence
Definition: ksinversion.cc:975
int nslicesahead
Definition: ksinversion.h:106

◆ ksinv_scan_sliceloop_flairblock()

s64 ksinv_scan_sliceloop_flairblock ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

[Internal ksinversion.cc] Plays out one repetition for an inversion scan

Parameters
[in]inv_loopctrlPointer to the inversion loop control
dynamicPointer to KS_DYNAMIC_STATE
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing the inversion function
Returns
slicelooptime Time taken in [us] to play out seq->slicetiming.state.slice_plan.nslices_per_pass slices
1098  {
1099  s64 time = 0;
1100  int i;
1101  int sltimeinpass = 0;
1102  const SCAN_INFO *slpos;
1103 
1104 #ifndef IPG
1105  if (inv_loopctrl == NULL) {
1106  KS_THROW("inversion seq (1st arg) cannot be NULL");
1107  return KS_NOTSET;
1108  }
1109  if (inv_loopctrl->irmode == KSINV_OFF) {
1110  return 0; /* if the IR mode for the 1st IR is off, return quietly */
1111  }
1112  if (inv_loopctrl->nflairslices <= 0) {
1113  KS_THROW("nflairslices must be > 0");
1114  return KS_NOTSET;
1115  }
1116 #endif
1117 
1118  /* For classic T2-FLAIR, we often end up with 2 sets of FLAIR+core per TR
1119  Here is a generalization, where number of sets is equal to:
1120  CEIL_DIV(inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass, inv_loopctrl->nflairslices), where inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass = CEIL_DIV(inv_loopctrl->loopctrl.slicetiming.slice_plan->nslices, inv_loopctrl->loopctrl.slicetiming.slice_plan->npasses)
1121  */
1122 
1123  /* make sure the step is positive, or else we will be stuck here as sltimeinpass will remain at 0 forever */
1124  const int slice_step = IMax(2, inv_loopctrl->nflairslices, 1);
1125 
1126  sltimeinpass = 0;
1127 
1128  while (sltimeinpass < inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass) {
1129 
1130  /*--------- inversion sequence module as FLAIR block -----------*/
1131  for (i = 0; i < inv_loopctrl->nflairslices; i++) {
1132  dynamic->slloc = ks_scan_getsliceloc(&inv_loopctrl->loopctrl.slicetiming.slice_plan, dynamic->pass, sltimeinpass + i);
1133  slpos = (dynamic->slloc != KS_NOTSET) ? &inv_loopctrl->loopctrl.slicetiming.rf_scan_info[dynamic->slloc] : NULL;
1134  time += irslice(slpos, dynamic).duration; /* if slpos = NULL, shut off RF */
1135  }
1136 
1137  for (i = 0; (i < inv_loopctrl->nflairslices) && ((sltimeinpass + i) < inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass); i++) {
1138 
1139  dynamic->slloc = ks_scan_getsliceloc(&inv_loopctrl->loopctrl.slicetiming.slice_plan, dynamic->pass, sltimeinpass + i);
1140  slpos = (dynamic->slloc != KS_NOTSET) ? &inv_loopctrl->loopctrl.slicetiming.rf_scan_info[dynamic->slloc] : NULL;
1141 
1142  /*--------- "coreslice": main sequence module (may include e.g. GRx Sat, FatSat etc.) -----------*/
1143 
1144  dynamic->sltimeinpass = (sltimeinpass + i);
1145  time += coreslice(slpos, dynamic).duration;
1146  }
1147 
1148  sltimeinpass += slice_step;
1149 
1150  if (inv_loopctrl->seqctrl_filltr.duration > 0) {
1151  /*--------- fillTR sequence module (to fill up to manual TR in CEIL_DIV(nslices_per_pass, inv_loopctrl->nflairslices) chunks) -----------*/
1152  time += ks_scan_playsequence(&inv_loopctrl->seqctrl_filltr);
1153  ks_plot_slicetime(&inv_loopctrl->seqctrl_filltr, 1, NULL, KS_NOTSET, KS_PLOT_NO_EXCITATION); /* Add a filler to slicetime plot */
1154  }
1155 
1156  } /* while */
1157 
1158  return time;
1159 
1160 } /* ksinv_scan_sliceloop_flairblock() */
SCAN_INFO rf_scan_info[KS_MAX_RF_SCANINFO]
Definition: ksscan.h:41
#define KS_NOTSET
Definition: KSFoundation.h:115
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int nflairslices
Definition: ksinversion.h:107
int irmode
Definition: ksinversion.h:103
int duration
Definition: KSFoundation.h:1227
int duration
Definition: ksscan.h:73
int nslices_per_pass
Definition: KSFoundation.h:1320
Definition: ksinversion.h:27
int ks_scan_playsequence(KS_SEQ_CONTROL *ctrl)
Definition: KSFoundation_tgt.c:1644
Definition: KSFoundation.h:404
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
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:1214
void ks_plot_slicetime(const KS_SEQ_CONTROL *ctrl, int nslices, float *slicepos_mm, float slthick_mm, KS_PLOT_EXCITATION_MODE exctype)
ADDTITLEHERE
Definition: KSFoundation_common.c:4276
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
KS_SEQ_CONTROL seqctrl_filltr
Definition: ksinversion.h:111

◆ ksinv_scan_sliceloop_sliceahead()

s64 ksinv_scan_sliceloop_sliceahead ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
int  nslicesahead_current,
int  nslicesahead_next,
int  play_core 
)

[Internal ksinversion.cc] Plays a single repetition of an interleaved inversion sequence

Parameters
inv_loopctrlPointer to the inversion loop control
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing an inversion (and optionally more) modules for a single inversion slice playout
[in]nslicesahead_currentOffset of the slice index used for inversion module(s) with respect to the one used for the core module(s). This is used only for inversions that will be sampled within the same repetition
[in]nslicesahead_nextOffset of the slice index used for inversion module(s) with respect to the one used for the core module(s). This is used only for inversions that will be sampled in the next repetition. Note that it is requred that nslicesahead_next <= nslicesahead_next.
[in]play_coreFlag indicating whether to turn on the acquisition of the core module
Return values
timeDuration in [us] to play out the scope of the function in real time
981  {
982  s64 time = 0;
983  int sltimeinpass = 0;
984  const SCAN_INFO *slpos;
985 
986 #ifndef IPG
987  if (inv_loopctrl == NULL) {
988  KS_THROW("inversion seq (1st arg) cannot be NULL");
989  return KS_NOTSET;
990  }
991  if (inv_loopctrl->irmode == KSINV_OFF) {
992  return 0; /* if the IR mode for the 1st IR is off, return quietly */
993  }
994  if (nslicesahead_current > inv_loopctrl->nslicesahead) {
995  KS_THROW("nslicesahead_current (%d) can not be higher than the evaluated nslicesahead (inv_loopctrl->nslicesahead = %d)",
996  nslicesahead_current, inv_loopctrl->nslicesahead);
997  return KS_NOTSET;
998  }
999  if (nslicesahead_next > nslicesahead_current && nslicesahead_current > 0) {
1000  KS_THROW("nslicesahead_next (%d) can not be higher than nslicesahead_current (%d)",
1001  nslicesahead_next, nslicesahead_current);
1002  return KS_NOTSET;
1003  }
1004 #endif
1005  const int total_slices_per_pass = inv_loopctrl->loopctrl.slicetiming.slice_plan.nslices_per_pass + inv_loopctrl->ndummy_slices_per_pass;
1006  const int sltime_start = (!play_core && nslicesahead_current < 0) ?
1007  (total_slices_per_pass - nslicesahead_next) : 0;
1008  const int current_pass_inv_end = nslicesahead_current < 0 ? 0 :
1009  total_slices_per_pass - nslicesahead_current;
1010  const int next_pass_inv_start = total_slices_per_pass -
1011  (nslicesahead_next < 0 ? 0 : nslicesahead_next);
1012 
1013  for (sltimeinpass = sltime_start; sltimeinpass < total_slices_per_pass; sltimeinpass++) {
1014 
1015  /*--------- inversion sequence module -----------*/
1016  dynamic->slloc = KS_NOTSET;
1017  if (sltimeinpass < current_pass_inv_end) {
1018  const int sltime_adjusted = sltimeinpass + nslicesahead_current - inv_loopctrl->ndummy_slices_per_pass;
1019  dynamic->slloc = ks_scan_getsliceloc(&inv_loopctrl->loopctrl.slicetiming.slice_plan, dynamic->pass, sltime_adjusted);
1020  }
1021  if (sltimeinpass >= next_pass_inv_start) {
1022  const int sltime_adjusted = (sltimeinpass + nslicesahead_next) % total_slices_per_pass - inv_loopctrl->ndummy_slices_per_pass;
1023  dynamic->slloc = ks_scan_getsliceloc(&inv_loopctrl->loopctrl.slicetiming.slice_plan, dynamic->pass, sltime_adjusted);
1024  }
1025  slpos = (dynamic->slloc != KS_NOTSET) ? &inv_loopctrl->loopctrl.slicetiming.rf_scan_info[dynamic->slloc] : NULL;
1026  time += irslice(slpos, dynamic).duration; /* if slpos = NULL, shut off RF */
1027 
1028  /*--------- "coreslice": main sequence module (may include e.g. GRx Sat, FatSat etc.) -----------*/
1029  dynamic->slloc = ks_scan_getsliceloc(&inv_loopctrl->loopctrl.slicetiming.slice_plan, dynamic->pass, sltimeinpass - inv_loopctrl->ndummy_slices_per_pass);
1030  slpos = (dynamic->slloc != KS_NOTSET) ? &inv_loopctrl->loopctrl.slicetiming.rf_scan_info[dynamic->slloc] : NULL;
1031  slpos = play_core ? slpos : NULL;
1032  dynamic->sltimeinpass = sltimeinpass - inv_loopctrl->ndummy_slices_per_pass;
1033  time += coreslice(slpos, dynamic).duration;
1034 
1035  } /* slice in pass */
1036 
1037  return time;
1038 
1039 } /* ksinv_scan_sliceloop_sliceahead() */
SCAN_INFO rf_scan_info[KS_MAX_RF_SCANINFO]
Definition: ksscan.h:41
#define KS_NOTSET
Definition: KSFoundation.h:115
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int irmode
Definition: ksinversion.h:103
int duration
Definition: ksscan.h:73
int nslices_per_pass
Definition: KSFoundation.h:1320
Definition: ksinversion.h:27
int ndummy_slices_per_pass
Definition: ksinversion.h:109
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
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:1214
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int nslicesahead
Definition: ksinversion.h:106

◆ ksinv_scan_acqloop()

s64 ksinv_scan_acqloop ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
const int  inv_rampup,
const int  inv_rampdown 
)

Plays out one pass/acquisition for an inversion scan

It affords the option to ramp up/down the inversions

Parameters
[in]inv_loopctrlPointer to the inversion loop control
[in,out]dynamicPointer to KS_DYNAMIC_STATE
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing an inversion (and optionally more) modules for a single inversion slice playout
[in]inv_rampupFlag for turning on the ramp up of the inversions at the beginning of the acquisition/pass
[in]inv_rampdownFlag for turning on the ramp down of the inversions at the end of the acquisition/pass
Return values
timeDuration in [us] to play out the scope of the function in real time
1201  {
1202 
1203  if (inv_loopctrl->irmode == KSINV_ON_FLAIR_BLOCK) {
1204  return ksinv_scan_acqloop_flairblock(inv_loopctrl,
1205  dynamic,
1206  coreslice,
1207  irslice);
1208  }
1209 
1210  const int nslicesahead_current = inv_loopctrl->nslicesahead;
1211  const int nslicesahead_next = inv_rampdown ? KS_NOTSET : inv_loopctrl->nslicesahead;
1212  return ksinv_scan_acqloop_sliceahead(inv_loopctrl,
1213  dynamic,
1214  coreslice,
1215  irslice,
1216  nslicesahead_current,
1217  nslicesahead_next,
1218  inv_rampup);
1219 } /* ksinv_scan_acqloop() */
s64 ksinv_scan_acqloop_flairblock(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
Definition: ksinversion.cc:1165
#define KS_NOTSET
Definition: KSFoundation.h:115
int irmode
Definition: ksinversion.h:103
Definition: ksinversion.h:27
s64 ksinv_scan_acqloop_sliceahead(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int nslicesahead_current, const int nslicesahead_next, const int inv_rampup)
Definition: ksinversion.cc:1044
int nslicesahead
Definition: ksinversion.h:106

◆ ksinv_scan_scanloop()

s64 ksinv_scan_scanloop ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

Plays the entire scan for an inversion loop control

Parameters
[in]inv_loopctrlPointer to the inversion loop control
[in,out]dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing the inversion function
Returns
time Duration in [us] to play out the scope of the function in real time

In a single pass scan we should ramp up/down only once. NOTE: this holds only if all sequences have the same slice encoding plan. – E.A.

1227  {
1228  s64 time = 0;
1229  const int dda = inv_loopctrl->loopctrl.dda;
1230 
1231  KS_DYNAMIC_STATE default_dynamic = KS_INIT_DYNAMIC_STATE;
1232  if (!dynamic) {
1233  dynamic = &default_dynamic;
1234  }
1235 
1236  for (dynamic->vol = 0; dynamic->vol < inv_loopctrl->loopctrl.nvols; dynamic->vol++) {
1237 
1242  const int inv_rampup =
1243  (inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses == 1 && dynamic->vol == 0)
1244  || inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses != 1;
1245 
1246  const int inv_rampdown =
1247  (inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses == 1 && dynamic->vol == inv_loopctrl->loopctrl.nvols - 1)
1248  || inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses != 1;
1249 
1250  for (dynamic->pass = 0; dynamic->pass < inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses; dynamic->pass++) {
1251 
1252  /* In a single pass scan we should play dummies only once */
1253  inv_loopctrl->loopctrl.dda = inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses == 1 ?
1254  (!dynamic->vol)*dda :
1255  dda;
1256 
1257  time += ksinv_scan_acqloop(inv_loopctrl, dynamic,
1258  coreslice, irslice,
1259  inv_rampup, inv_rampdown);
1260 
1261  inv_loopctrl->loopctrl.dda = 0;
1262  if (inv_loopctrl->loopctrl.play_endofpass) {
1263  time += GEReq_endofpass();
1264  }
1266 
1267  } /* pass loop */
1268 
1269  } /* volume loop */
1270 
1271  /* restore #dummies */
1272  inv_loopctrl->loopctrl.dda = dda;
1273 
1274  return time; /* in [us] */
1275 
1276 } /* ksinv_scan_scanloop() */
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int play_endofpass
Definition: ksscan.h:188
int dda
Definition: ksscan.h:185
int npasses
Definition: KSFoundation.h:1319
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
s64 ksinv_scan_acqloop(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int inv_rampup, const int inv_rampdown)
Plays out one pass/acquisition for an inversion scan
Definition: ksinversion.cc:1197
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:3621
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_common.c:4286
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
Definition: KSFoundation.h:409
int nvols
Definition: ksscan.h:186
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42

◆ ksinv_prescanloop()

void ksinv_prescanloop ( KSINV_LOOP_CONTROL inv_loopctrl,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
int  nloops,
int  dda 
)

Prescan loop for inversion

Parameters
[in]inv_loopctrlPointer to the inversion loop control
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing the inversion function
[in]nloopsADDTEXTHERE
[in]ddaADDTEXTHERE
Returns
void

Prescan loop for inversion

1288  {
1289 
1291  KS_DYNAMIC_STATE dynamic = KS_INIT_DYNAMIC_STATE;
1292  dynamic.prescan = 1;
1293  dynamic.shot_coords = fake_shot;
1294 
1295  if (inv_loopctrl->nslicesahead) {
1296  /* sliceahead inversion prologue (KSINV_LOOP_SLICEAHEAD_FIRST) */
1297 
1298  KS_DYNAMIC_STATE dynamic_sliceahead = KS_INIT_DYNAMIC_STATE; /* Everything is KS_NOTSET */
1299  ksinv_scan_sliceloop(inv_loopctrl, &dynamic_sliceahead, KSINV_LOOP_SLICEAHEAD_FIRST, coreslice, irslice);
1300  }
1301 
1302  int i;
1303  for (i = -dda; i < nloops; i++) {
1304  /* negative shot always closes data receiver during prescan */
1305  dynamic.shot = (dda < 0) * KS_NOTSET;
1306  ksinv_scan_sliceloop(inv_loopctrl, &dynamic, KSINV_LOOP_NORMAL, coreslice, irslice);
1307  } /* for nloops */
1308 
1309 } /* ksscan_prescanloop_custom() */
ADDTITLEHERE
Definition: KSFoundation.h:1773
#define KS_NOTSET
Definition: KSFoundation.h:115
Definition: ksinversion.h:28
s64 ksinv_scan_sliceloop(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KSINV_LOOP_MODE ksinv_loop_mode, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
Plays a single repetition of an inversion sequence
Definition: ksinversion.cc:944
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
#define KS_INIT_PHASEENCODING_SHOTCOORDS
Definition: KSFoundation.h:1778
Definition: ksinversion.h:28
int nslicesahead
Definition: ksinversion.h:106

◆ ksinv_eval_chain_design()

STATUS ksinv_eval_chain_design ( KSINV_CHAIN inv_chain,
KSINV_CHAIN_DESIGN inv_chain_design,
const KSINV_LOOP_CONTROL inv_loopctrl 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
inv_chainADDTEXTHERE
inv_chain_designADDTEXTHERE
inv_loopctrlADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
730  {
731 
732  STATUS status;
733 
734  if (!inv_chain || !inv_chain_design || !inv_loopctrl) {
735  return KS_THROW("NULL input");
736  }
737 
738  if (inv_loopctrl->irmode == KSINV_OFF || inv_chain_design->num_vols < 1) {
739  return SUCCESS;
740  }
741 
742  if (inv_loopctrl->nslicesahead < 1 || inv_loopctrl->irmode == KSINV_ON_FLAIR_BLOCK) {
743  return KS_THROW("Inversion chain is only compatible with slice ahead mode (KSINV_ON_INTERLEAVED)");
744  }
745 
746  /* TODO: sort the individual volume designs so that T2w always come first and then nslicesahead is decreasing? */
747 
748  /* Copy fields */
749  inv_chain->num_vols = inv_chain_design->num_vols;
750 
751  int i;
752  for (i=0; i<inv_chain->num_vols; ++i) {
753  if (inv_chain_design->nslicesaheads[i] > inv_loopctrl->nslicesahead) {
754  return KS_THROW("A requested nslicesahead can not exceed the value from inv_loopctrl");
755  }
756 
757  inv_chain->inv_vols[i].nslicesahead = inv_chain_design->nslicesaheads[i];
758  inv_chain->inv_vols[i].dda = inv_chain_design->ddas[i];
759  inv_chain->inv_vols[i].echo_offset = inv_chain_design->echo_offsets[i];
760 
761  if (inv_chain_design->phaseenc_plan_designs[i].kacq.coords) {
762 
763  /* TODO: check if num_encodes is the same for all vols? */
764 
766  &inv_chain_design->phaseenc_plan_designs[i]);
767  KS_RAISE(status);
768  } else {
769  /* Copy from the inversion loop control */
770  inv_chain->inv_vols[i].phaseenc_plan = inv_loopctrl->loopctrl.phaseenc_plan;
771  }
772  }
773 
774  return SUCCESS;
775 }
STATUS ksscan_phaseencoding_plan_eval_design(KS_PHASEENCODING_PLAN *pe_plan, const KS_PHASEENCODING_PLAN_DESIGN *design)
Generates a phase encodin plan according to design
Definition: ksscan.cc:26
int nslicesaheads[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:582
KSINV_MULTI_INV_VOL inv_vols[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:611
int num_vols
Definition: ksinversion.h:610
KS_KSPACE_ACQ kacq
Definition: ksscan.h:138
int num_vols
Definition: ksinversion.h:581
int dda
Definition: ksinversion.h:599
KS_KCOORD * coords
Definition: KSFoundation.h:2228
int irmode
Definition: ksinversion.h:103
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksinversion.h:598
KS_PHASEENCODING_PLAN_DESIGN phaseenc_plan_designs[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:583
int nslicesahead
Definition: ksinversion.h:597
int echo_offset
Definition: ksinversion.h:600
Definition: ksinversion.h:27
int echo_offsets[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:585
#define KS_RAISE(status)
Definition: KSFoundation.h:190
int ddas[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:584
Definition: ksinversion.h:27
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksscan.h:190
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int nslicesahead
Definition: ksinversion.h:106

◆ ksinv_scan_acqloop_chain()

s64 ksinv_scan_acqloop_chain ( const KSINV_CHAIN inv_chain,
KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
inv_chainADDTEXTHERE
inv_loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing the inversion function
Returns
time Duration in [us] to play out the scope of the function in real time
1318  {
1319 
1320  s64 time = 0;
1321 
1322  /* Save fields that need to be updated */
1323  const int orig_dda = inv_loopctrl->loopctrl.dda;
1324  const KS_PHASEENCODING_PLAN orig_phaseenc_plan = inv_loopctrl->loopctrl.phaseenc_plan;
1325  const int orig_echo_offset = dynamic->echo_offset;
1326 
1327  int inv_rampup = inv_chain->inv_vols[0].nslicesahead > 0;
1328 
1329  int i = 0;
1330  for (; i < inv_chain->num_vols; ++i) {
1331 
1332  /* Update fields */
1333  inv_loopctrl->loopctrl.dda = inv_chain->inv_vols[i].dda;
1334  inv_loopctrl->loopctrl.phaseenc_plan = inv_chain->inv_vols[i].phaseenc_plan;
1335  dynamic->echo_offset = orig_echo_offset + inv_chain->inv_vols[i].echo_offset;
1336 
1337  const int nslicesahead_next = i+1 == inv_chain->num_vols ? KS_NOTSET : inv_chain->inv_vols[i+1].nslicesahead;
1338 
1339  time += ksinv_scan_acqloop_sliceahead(inv_loopctrl,
1340  dynamic,
1341  coreslice,
1342  irslice,
1343  inv_chain->inv_vols[i].nslicesahead,
1344  nslicesahead_next,
1345  inv_rampup);
1346 
1347  inv_rampup = 0;
1348  }
1349 
1350  /* Restore fields that need to be updated */
1351  inv_loopctrl->loopctrl.dda = orig_dda;
1352  inv_loopctrl->loopctrl.phaseenc_plan = orig_phaseenc_plan;
1353  dynamic->echo_offset = orig_echo_offset;
1354 
1355  return time;
1356 
1357 } /* ksinv_scan_acqloop_chain() */
KSINV_MULTI_INV_VOL inv_vols[KSINV_MULTI_INV_MAX_NUM_VOLS]
Definition: ksinversion.h:611
int num_vols
Definition: ksinversion.h:610
ADDTITLEHERE
Definition: KSFoundation.h:1787
#define KS_NOTSET
Definition: KSFoundation.h:115
int dda
Definition: ksinversion.h:599
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksinversion.h:598
int nslicesahead
Definition: ksinversion.h:597
int dda
Definition: ksscan.h:185
int echo_offset
Definition: ksinversion.h:600
KS_PHASEENCODING_PLAN phaseenc_plan
Definition: ksscan.h:190
s64 ksinv_scan_acqloop_sliceahead(KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), const int nslicesahead_current, const int nslicesahead_next, const int inv_rampup)
Definition: ksinversion.cc:1044
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110

◆ ksinv_scan_scanloop_chain()

s64 ksinv_scan_scanloop_chain ( const KSINV_CHAIN inv_chain,
KSINV_LOOP_CONTROL inv_loopctrl,
KS_DYNAMIC_STATE *  dynamic,
KS_CORESLICETIME   coresliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic,
KS_CORESLICETIME   irsliceconst SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
inv_chainADDTEXTHERE
inv_loopctrlADDTEXTHERE
dynamicPointer to KS_DYNAMIC_STATE struct, which has elements being automatically updated by the scan looping functions
[in]coresliceFunction pointer to function playing one or more sequence modules for a single playout
[in]irsliceFunction pointer to function playing the inversion function
Returns
time Duration in [us] to play out the scope of the function in real time
1366  {
1367 
1368  s64 time = 0;
1369 
1370  KS_DYNAMIC_STATE default_dynamic = KS_INIT_DYNAMIC_STATE;
1371  if (!dynamic) {
1372  dynamic = &default_dynamic;
1373  }
1374 
1375  for (dynamic->vol = 0; dynamic->vol < inv_loopctrl->loopctrl.nvols; dynamic->vol++) {
1376  for (dynamic->pass = 0; dynamic->pass < inv_loopctrl->loopctrl.slicetiming.slice_plan.npasses; dynamic->pass++) {
1377 
1378  time += ksinv_scan_acqloop_chain(inv_chain,
1379  inv_loopctrl,
1380  dynamic,
1381  coreslice,
1382  irslice);
1383 
1384  if (inv_loopctrl->loopctrl.play_endofpass) {
1385  time += GEReq_endofpass();
1386  }
1388  }
1389  }
1390 
1391  return time;
1392 
1393 } /* ksinv_scan_scanloop_chain() */
KS_SLICETIMING slicetiming
Definition: ksscan.h:192
int play_endofpass
Definition: ksscan.h:188
s64 ksinv_scan_acqloop_chain(const KSINV_CHAIN *inv_chain, KSINV_LOOP_CONTROL *inv_loopctrl, KS_DYNAMIC_STATE *dynamic, KS_CORESLICETIME coreslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic), KS_CORESLICETIME irslice(const SCAN_INFO *slice_pos, KS_DYNAMIC_STATE *dynamic))
ADDTITLEHERE
Definition: ksinversion.cc:1314
int npasses
Definition: KSFoundation.h:1319
#define KS_INIT_DYNAMIC_STATE
Definition: KSFoundation.h:1829
int GEReq_endofpass()
Sets SSP word in sequence off_GEpass() to trigger data (Pfile) writing and reconstruction
Definition: GERequired.e:3621
void ks_plot_slicetime_endofpass(KS_PLOT_PASS_MODE pass_mode)
ADDTITLEHERE
Definition: KSFoundation_common.c:4286
KSSCAN_LOOP_CONTROL loopctrl
Definition: ksinversion.h:110
Definition: KSFoundation.h:409
int nvols
Definition: ksscan.h:186
KS_SLICE_PLAN slice_plan
Definition: ksscan.h:42