KSFoundation  [October2024]
A platform for structured EPIC programming on GE MR systems
ksepg.cc File Reference
#include <ksepg.h>
#include <stdlib.h>
#include <math.h>
int rhkacq_uid
 
int ks_plot_filefmt
 
int ks_plot_kstmp
 
char ks_psdname [256]
 
KSEPG_RELAXATION ksepg_create_relaxation (double time_delta, double T1, double T2)
 
KSEPG_STATE ksepg_create_state (int size)
 
void ksepg_destruct_state (KSEPG_STATE *state)
 
KSEPG_STATE ksepg_duplicate_state (const KSEPG_STATE *state)
 
void ksepg_dephase (KSEPG_STATE *state, KSEPG_RELAXATION rel_op)
 
void ksepg_compute_rotation (KS_MAT3x3 *rot, double flip)
 
void ksepg_apply_rotation (KSEPG_STATE *state, KS_MAT3x3 *rot_p)
 
void ksepg_refocus (KSEPG_STATE *state, KS_MAT3x3 *rot)
 
void ksepg_next_echo (KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
 
STATUS ksepg_get_intensities (const double *flip_angles, int num_echoes, KSEPG_STATE state, double *signal_intensities, double echo_spacing, double T1, double T2)
 
STATUS ksepg_get_intensities_std (const double *flip_angles, double *signal_intensities, int num_echoes, double echo_spacing, double T1, double T2)
 
STATUS ksepg_get_intensities_long (const double *flip_angles, double *signal_intensities, int num_echoes, double echo_spacing, double T1, double T2)
 
double ksepg_solve_trig_eq (double a, double b, double c)
 
double ksepg_track_step (double Fp, double Fm, double Z, double target_Fm, KSEPG_RELAXATION rel_op)
 
STATUS ksepg_track_intensity_curve (double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
 
STATUS ksepg_track_intensity_std (double *flip_angles, int num_echoes, double target_intensity, double echo_spacing, double T1, double T2)
 
STATUS ksepg_track_intensity_long (double *flip_angles, int num_echoes, double target_intensity, double echo_spacing, double T1, double T2)
 
void ks_print_epg_sim (const float *flip_angles, const double *si_rel, const double *si_norel, const double *effTEs, const int num_echoes, const double echo_spacing, const double T1, const double T2, KS_DESCRIPTION description)
 
void ks_predownload_plot_epg_sim (KS_DESCRIPTION description)
 
STATUS ksepg_calc_effTE (const float *flip_angles, double *effTEs, int num_echoes, double echo_spacing, double T1, double T2, KS_DESCRIPTION description)
 
double ksepg_max_angle (double *flip_angles, int num_echoes)
 
STATUS ksepg_optimize_constant (double *intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_constant_std (double *intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2)
 
STATUS ksepg_optimize_constant_long (double *intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2)
 
STATUS ksepg_generate_intensity_triangle_impl (double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity, double half_size)
 
STATUS ksepg_generate_intensity_periodic_triangle (double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
 
STATUS ksepg_generate_intensity_cropped_triangle (double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
 
STATUS ksepg_generate_intensity_ramp (double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
 
STATUS ksepg_generate_intensity_linear (double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
 
STATUS ksepg_track_bounded_curve (double *flip_angles, double *target_intensities, int num_echoes, double min_intensity, double max_intensity, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_bounded_curve (double *min_intensity, double *max_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_bounded_curve_std (double *min_intensity, double *max_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double))
 
STATUS ksepg_optimize_bounded_curve_long (double *min_intensity, double *max_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double))
 
STATUS ksepg_optimize_rampdown (double *end_intensity, double start_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
 
STATUS ksepg_half_intensity (double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, KSEPG_TAIL tail_type)
 
STATUS ksepg_optimize_expdown (double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_half_exponential (double *flip_angles, int num_echoes, double max_flip)
 
STATUS ksepg_optimize_half_free (double *flip_angles, int num_echoes, double max_flip)
 
STATUS ksepg_optimize_linear_free (double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_linear_free_std (double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2)
 
STATUS ksepg_optimize_linear_free_long (double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2)
 
STATUS ksepg_optimize_linear_free_center_echo (int *_center_echo, int target_eff_TE, int linear_sweep_center_echo, double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
 
STATUS ksepg_optimize_linear_free_center_echo_std (int *center_echo, int target_eff_TE, int linear_sweep_center_echo, double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2)
 
STATUS ksepg_optimize_linear_free_center_echo_long (int *center_echo, int target_eff_TE, int linear_sweep_center_echo, double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2)
 
STATUS ksepg_sineTRAPS (double *flip_angles, int etl, int n23, int n4, double an1, double an23, double an4)
 
STATUS ksepg_sineTRAPS2 (float *flip_angles, int etl, KSEPG_TRAPS_DESIGN traps_design, float scaling_factor)
 
double ksepg_calc_relSAR (double *flip_angles, int etl)
 

Detailed Description

This file contains sequence-independent implementations for extended phase graphs

Feature module: Extended Phase Graphs (ksepg.[h,cc])

Function Documentation

◆ ksepg_create_relaxation()

KSEPG_RELAXATION ksepg_create_relaxation ( double  time_delta,
double  T1,
double  T2 
)

Create a relaxation operator

Parameters
[in]time_deltaTime interval over whivh relaxation occurs
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
Returns
KSEPG_RELAXATION
31  {
32 
33  KSEPG_RELAXATION rel_op;
34  rel_op.decayT1 = T1 <= 0 ? 1 : exp(-time_delta/T1);
35  rel_op.decayT2 = T2 <= 0 ? 1 : exp(-time_delta/T2);
36 
37  return rel_op;
38 
39 } /* ksepg_create_relaxation() */
double decayT1
Definition: ksepg.h:55
Relaxation operator
Definition: ksepg.h:54
double decayT2
Definition: ksepg.h:56

◆ ksepg_create_state()

KSEPG_STATE ksepg_create_state ( int  size)

Create a new EPG state with a certain maximum number of dephasing steps

Parameters
[in]sizeMaximum number of dephasing steps to be modeled
Returns
KSEPG_STATE
44  {
45 
46  KSEPG_STATE state;
47  state.size = size;
48  state.data = (double*)calloc(3*size, sizeof(double));
49 
50  return state;
51 
52 } /* ksepg_create_state() */
int size
Definition: ksepg.h:42
double * data
Definition: ksepg.h:43
Extended phase graph state
Definition: ksepg.h:41

◆ ksepg_destruct_state()

void ksepg_destruct_state ( KSEPG_STATE state)

Free an EPG state's memory

Parameters
[in,out]state
57  {
58 
59  free(state->data);
60 
61 } /* ksepg_destruct_state() */
double * data
Definition: ksepg.h:43

◆ ksepg_duplicate_state()

KSEPG_STATE ksepg_duplicate_state ( const KSEPG_STATE state)

Duplicate an EPG's state

Parameters
[in]stateto duplicate
Returns
duplicate state
66  {
67 
68  KSEPG_STATE duplicate = ksepg_create_state(state->size);
69 
70  int i = 0;
71  for (; i<3*duplicate.size; ++i) {
72  duplicate.data[i] = state->data[i];
73  }
74 
75  return duplicate;
76 
77 } /* ksepg_duplicate_state() */
int size
Definition: ksepg.h:42
double * data
Definition: ksepg.h:43
Extended phase graph state
Definition: ksepg.h:41
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_dephase()

void ksepg_dephase ( KSEPG_STATE state,
KSEPG_RELAXATION  rel_op 
)

Apply a dephasing step and a relaxation operator to an EPG state

The dephasing step shifts F_+ to the right and F_- to the left.

Parameters
[in,out]state
[in]rel_op
82  {
83 
84  int i;
85  int size = state->size;
86  double *data = state->data;
87 
88  /* shift F_+ to the right */
89  for (i=1; i<size; ++i) {
90  data[3*(size-i)] = rel_op.decayT2 * data[3*(size-i-1)];
91  }
92 
93  /* shift F_- to the left */
94  for (i=0; i<size-1; ++i) {
95  data[3*i + 1] = rel_op.decayT2 * data[3*(i+1) + 1];
96  }
97  data[3*(size-1) + 1] = 0;
98 
99  /* F_+(0) is equal to F_-(0) */
100  data[0] = data[1];
101 
102  /* apply T1 decay/recovery */
103  for (i=0; i<size; ++i) {
104  data[3*i + 2] *= rel_op.decayT1;
105  }
106  data[2] += 1-rel_op.decayT1;
107 
108 } /* ksepg_dephase() */
int size
Definition: ksepg.h:42
double * data
Definition: ksepg.h:43
double decayT1
Definition: ksepg.h:55
double decayT2
Definition: ksepg.h:56

◆ ksepg_compute_rotation()

void ksepg_compute_rotation ( KS_MAT3x3 rot,
double  flip 
)

Compute the rotation matrix corresponding to a refocusing pulse

Parameters
[out]rotThe computed rotation matrix
[in]flipFlip angle of the refocusing pulse
113  {
114 
115  double c = cos(flip);
116  double s = sin(flip);
117  double cc = (1+c)/2;
118  double ss = (1-c)/2;
119 
120  double *r = *rot;
121  r[0] = cc;
122  r[1] = ss;
123  r[2] = -s;
124 
125  r[3] = ss;
126  r[4] = cc;
127  r[5] = s;
128 
129  r[6] = s/2;
130  r[7] = -s/2;
131  r[8] = c;
132 
133 } /* ksepg_compute_rotation() */

◆ ksepg_apply_rotation()

void ksepg_apply_rotation ( KSEPG_STATE state,
KS_MAT3x3 rot 
)

Apply a rotation matrix to an EPG state

Parameters
[in,out]state
[in]rot
138  {
139 
140  int i, k;
141  int size = state->size;
142  double *data = state->data;
143  const double *rot = *rot_p;
144  double tmp[3];
145 
146  for (i=0; i<size; ++i) {
147 
148  for (k=0; k<3; ++k) {
149  tmp[k] = data[3*i]*rot[3*k] + data[3*i+1]*rot[3*k+1] + data[3*i+2]*rot[3*k+2];
150  }
151 
152  for (k=0; k<3; ++k) {
153  data[3*i+k] = tmp[k];
154  }
155  }
156 
157 } /* ksepg_apply_rotation() */
int size
Definition: ksepg.h:42
double * data
Definition: ksepg.h:43

◆ ksepg_refocus()

void ksepg_refocus ( KSEPG_STATE state,
KS_MAT3x3 rot 
)

Apply a refocusing operator to an EPG state

This operation differ from ksepg_apply_rotation in that it includes the effect of the crushers.

Parameters
[in,out]state
[in]rotThe rotation matrix corresponding to the refocusing pulse
162  {
163 
164  ksepg_apply_rotation(state, rot);
165 
166  /* apply crushers */
167  state->data[0] = 0;
168  state->data[1] = 0;
169 
170 } /* ksepg_refocus() */
double * data
Definition: ksepg.h:43
void ksepg_apply_rotation(KSEPG_STATE *state, KS_MAT3x3 *rot_p)
Apply a rotation matrix to an EPG state
Definition: ksepg.cc:138

◆ ksepg_next_echo()

void ksepg_next_echo ( KSEPG_STATE state,
KS_MAT3x3 rot,
KSEPG_RELAXATION  rel_op 
)

Advance the EPG state from an echo to the next

Parameters
[in,out]state
[in]rotThe rotation matrix corresponding to the refocusing pulse between the two echoes
[in]rel_opRelaxation operator corresponding to a periof equal to half of the echo spacing
175  {
176 
177  ksepg_dephase(state, rel_op);
178  ksepg_refocus(state, rot);
179  ksepg_dephase(state, rel_op);
180 
181 } /* ksepg_next_echo() */
void ksepg_refocus(KSEPG_STATE *state, KS_MAT3x3 *rot)
Apply a refocusing operator to an EPG state
Definition: ksepg.cc:162
void ksepg_dephase(KSEPG_STATE *state, KSEPG_RELAXATION rel_op)
Apply a dephasing step and a relaxation operator to an EPG state
Definition: ksepg.cc:82

◆ ksepg_get_intensities()

STATUS ksepg_get_intensities ( const double *  flip_angles,
int  num_echoes,
KSEPG_STATE  state,
double *  signal_intensities,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]stateADDTEXTHERE
signal_intensitiesADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
189  {
190 
191  if (!flip_angles || !state.data) { return KS_THROW("No flip-angle or state array found"); }
192 
193  KS_MAT3x3 rot;
194  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
195 
196  int i;
197  for (i=0; i<num_echoes; ++i) {
198  /* advance the state to before the refocusing */
199  ksepg_dephase(&state, rel);
200 
201  double flip = flip_angles[i];
202  /* ensuring it is not NaN */
203  if (isNaN(flip)) {
204  return KS_THROW("flip_angles[%d] is NaN", i);
205  }
206 
207  /* advance the state to the next echo */
208  ksepg_compute_rotation(&rot, flip);
209  ksepg_refocus(&state, &rot);
210  ksepg_dephase(&state, rel);
211 
212  /* save refocused signal intensity (state.data[0] and state.data[1] should be equal) */
213  if (signal_intensities) {
214  signal_intensities[i] = state.data[1];
215  }
216  }
217 
218  return SUCCESS;
219 
220 } /* ksepg_get_intensities() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
void ksepg_refocus(KSEPG_STATE *state, KS_MAT3x3 *rot)
Apply a refocusing operator to an EPG state
Definition: ksepg.cc:162
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_dephase(KSEPG_STATE *state, KSEPG_RELAXATION rel_op)
Apply a dephasing step and a relaxation operator to an EPG state
Definition: ksepg.cc:82
int isNaN(float a)
Definition: KSFoundation_common.c:58
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_get_intensities_std()

STATUS ksepg_get_intensities_std ( const double *  flip_angles,
double *  signal_intensities,
int  num_echoes,
double  echo_spacing,
double  T1,
double  T2 
)

Simulate a classic FSE train with EPG to compute the signal intensities

Parameters
[in]flip_anglesRefocusing flip angles
[out]signal_intensitiesThe intensity levels for each echo relative to T=0
[in]num_echoesNumber of echoes in the train
[in]echo_spacingEcho spacing for the FSE train
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
Return values
STATUSSUCCESS or FAILURE
226  {
227 
228  if (!flip_angles || !signal_intensities) { KS_RAISE(FAILURE); }
229 
230  const int state_size = 2*num_echoes + 1;
231 
232  /* initialize the state to the value after the excitation */
233  KSEPG_STATE state = ksepg_create_state(state_size);
234  state.data[0] = 1;
235  state.data[1] = 1;
236 
237  /* calc signal intensites */
238  STATUS status = ksepg_get_intensities(flip_angles, num_echoes,
239  state,
240  signal_intensities,
241  echo_spacing, T1, T2);
242 
243  /* free memory */
244  ksepg_destruct_state(&state);
245 
246  KS_RAISE(status);
247 
248  return SUCCESS;
249 
250 } /* ksepg_get_intensites_std() */
double * data
Definition: ksepg.h:43
STATUS ksepg_get_intensities(const double *flip_angles, int num_echoes, KSEPG_STATE state, double *signal_intensities, double echo_spacing, double T1, double T2)
ADDTITLEHERE
Definition: ksepg.cc:186
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_get_intensities_long()

STATUS ksepg_get_intensities_long ( const double *  flip_angles,
double *  signal_intensities,
int  num_echoes,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
signal_intensitiesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
256  {
257 
258  if (!flip_angles || !signal_intensities) { KS_RAISE(FAILURE); }
259 
260  const int state_size = 2*num_echoes + 3;
261 
262  KS_MAT3x3 rot;
263  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
264 
265  /* initialize the state to the value after the excitation */
266  KSEPG_STATE state = ksepg_create_state(state_size);
267  state.data[0] = 1;
268  state.data[1] = 1;
269 
270  /* apply a first refocusing of 90 degrees */
271  ksepg_compute_rotation(&rot, PI/2);
272  ksepg_next_echo(&state, &rot, rel);
273 
274  /* calc signal intensites */
275  STATUS status = ksepg_get_intensities(flip_angles, num_echoes,
276  state,
277  signal_intensities,
278  echo_spacing, T1, T2);
279 
280  /* free memory */
281  ksepg_destruct_state(&state);
282 
283  KS_RAISE(status);
284 
285  return SUCCESS;
286 
287 } /* ksepg_get_intensities_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
STATUS ksepg_get_intensities(const double *flip_angles, int num_echoes, KSEPG_STATE state, double *signal_intensities, double echo_spacing, double T1, double T2)
ADDTITLEHERE
Definition: ksepg.cc:186
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_solve_trig_eq()

double ksepg_solve_trig_eq ( double  a,
double  b,
double  c 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
[in]aADDTEXTHERE
[in]bADDTEXTHERE
cADDTEXTHERE
Return values
valueADDTEXTHERE
292  {
293 
294  double R = sqrt(a*a + b*b);
295  double beta = atan2(b, a);
296  return asin(c/R) - beta;
297 
298 } /* ksepg_solve_trig_eq() */

◆ ksepg_track_step()

double ksepg_track_step ( double  Fp,
double  Fm,
double  Z,
double  target_Fm,
KSEPG_RELAXATION  rel_op 
)

Attempt to track a target intensity

Attempt to select a refocusing flip angle so that F_-(0) will match a desired target intensity at the next echo.

Parameters
[in]FpF_+(1) just before the refocusing pulse
[in]FmF_-(1) just before the refocusing pulse
[in]ZZ(1) just before the refocusing pulse
[in]target_FmTarget for F_-(0) after the refocusing pulse and a dephasing step
[in]rel_opRelaxation operator over the dephasing time
Returns
double Flip angle that tracks the target, NaN if it is not feasible
303  {
304 
305  double a = Z;
306  double b = (Fm - Fp)/2;
307  double c = target_Fm/rel_op.decayT2 - (Fm + Fp)/2;
308 
309  return ksepg_solve_trig_eq(a, b, c);
310 
311 } /* ksepg_track_step() */
double ksepg_solve_trig_eq(double a, double b, double c)
ADDTITLEHERE
Definition: ksepg.cc:292
double decayT2
Definition: ksepg.h:56

◆ ksepg_track_intensity_curve()

STATUS ksepg_track_intensity_curve ( double *  flip_angles,
int  num_echoes,
KSEPG_STATE  state,
double  scaling_factor,
const double *  target_curve,
double  echo_spacing,
double  T1,
double  T2 
)

Track the requested intensity curve with a custom starting EPG state

This function attempt to set the refocusing flip angle so that the signal intensity of a certain tissue follows over the echoes the requested curve scaled by a factor.

Parameters
[out]flip_anglesRefocusing flip angle
[in]num_echoesNumber of echoes in the train
[in,out]stateEPG state that will be updated
[in]scaling_factorScaling factor for the intensity curve
[in]target_curveTarget intensity curve to be matched. If NULL it is assumed to be a constant curve equal to one.
[in]echo_spacingEcho spacing for the FSE train
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
Return values
STATUSSUCCESS or FAILURE
320  {
321 
322  if (!flip_angles || !state.data) { return KS_THROW("No flip-angle or state array found"); }
323 
324  KS_MAT3x3 rot;
325  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
326 
327  int i;
328  for (i=0; i<num_echoes; ++i) {
329  /* advance the state to before the refocusing */
330  ksepg_dephase(&state, rel);
331 
332  double flip;
333  if (target_curve == NULL) {
334  flip = ksepg_track_step(state.data[3], state.data[4], state.data[5], scaling_factor, rel);
335  } else {
336  flip = ksepg_track_step(state.data[3], state.data[4], state.data[5], target_curve[i]*scaling_factor, rel);
337  }
338 
339  flip_angles[i] = flip;
340  /* ensuring it is not NaN */
341  if (isNaN(flip)) {
342  return FAILURE;
343  }
344 
345  /* advance the state to the next echo */
346  ksepg_compute_rotation(&rot, flip);
347  ksepg_refocus(&state, &rot);
348  ksepg_dephase(&state, rel);
349  }
350 
351  return SUCCESS;
352 
353 } /* ksepg_track_intensity_curve() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
void ksepg_refocus(KSEPG_STATE *state, KS_MAT3x3 *rot)
Apply a refocusing operator to an EPG state
Definition: ksepg.cc:162
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_dephase(KSEPG_STATE *state, KSEPG_RELAXATION rel_op)
Apply a dephasing step and a relaxation operator to an EPG state
Definition: ksepg.cc:82
int isNaN(float a)
Definition: KSFoundation_common.c:58
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
double ksepg_track_step(double Fp, double Fm, double Z, double target_Fm, KSEPG_RELAXATION rel_op)
Attempt to track a target intensity
Definition: ksepg.cc:303

◆ ksepg_track_intensity_std()

STATUS ksepg_track_intensity_std ( double *  flip_angles,
int  num_echoes,
double  target_intensity,
double  echo_spacing,
double  T1,
double  T2 
)

Track the requested intensity level with a classic FSE train

This function attempt to set the refocusing flip angle so that the signal intensity of a certain tissue is constant over all echoes.

Parameters
[out]flip_anglesRefocusing flip angle
[in]num_echoesNumber of echoes in the train
[in]target_intensityTarget intensity relative to T=0, must be in (0,1)
[in]echo_spacingEcho spacing for the FSE train
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
Return values
STATUSSUCCESS or FAILURE
360  {
361 
362  if (!flip_angles) { return FAILURE; }
363 
364  const int state_size = 2*num_echoes + 1;
365 
366  /* initialize the state to the value after the excitation */
367  KSEPG_STATE state = ksepg_create_state(state_size);
368  state.data[0] = 1;
369  state.data[1] = 1;
370 
371  STATUS s = ksepg_track_intensity_curve(flip_angles, num_echoes,
372  state,
373  target_intensity,
374  NULL,
375  echo_spacing, T1, T2);
376  ksepg_destruct_state(&state);
377 
378  return s;
379 
380 } /* ksepg_track_intensity_std() */
double * data
Definition: ksepg.h:43
STATUS ksepg_track_intensity_curve(double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
Track the requested intensity curve with a custom starting EPG state
Definition: ksepg.cc:316
Extended phase graph state
Definition: ksepg.h:41
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_track_intensity_long()

STATUS ksepg_track_intensity_long ( double *  flip_angles,
int  num_echoes,
double  target_intensity,
double  echo_spacing,
double  T1,
double  T2 
)

Track the requested intensity level with an extended FSE train

Track the requested intensity level with a modified FSE train where an extra echo with a 90 degree refocusing is inserted at the beginng. It is better suited for long echo trains.

NOTE that the extra echo's data is not meant to be measured.

Parameters
[out]flip_anglesRefocusing flip angle
[in]num_echoesNumber of echoes in the train
[in]target_intensityTarget intensity relative to T=0, must be in (0,1)
[in]echo_spacingEcho spacing for the FSE train
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
Return values
STATUSSUCCESS or FAILURE
387  {
388 
389  if (!flip_angles) { return FAILURE; }
390 
391  const int state_size = 2*num_echoes + 3;
392 
393  KS_MAT3x3 rot;
394  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
395 
396  /* initialize the state to the value after the excitation */
397  KSEPG_STATE state = ksepg_create_state(state_size);
398  state.data[0] = 1;
399  state.data[1] = 1;
400 
401  /* apply a first refocusing of 90 degrees */
402  ksepg_compute_rotation(&rot, PI/2);
403  ksepg_next_echo(&state, &rot, rel);
404 
405  STATUS s = ksepg_track_intensity_curve(flip_angles, num_echoes,
406  state,
407  target_intensity,
408  NULL,
409  echo_spacing, T1, T2);
410  ksepg_destruct_state(&state);
411 
412  return s;
413 
414 } /* ksepg_track_intensity_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
STATUS ksepg_track_intensity_curve(double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
Track the requested intensity curve with a custom starting EPG state
Definition: ksepg.cc:316
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
Extended phase graph state
Definition: ksepg.h:41
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ks_print_epg_sim()

void ks_print_epg_sim ( const float *  flip_angles,
const double *  si_rel,
const double *  si_norel,
const double *  effTEs,
const int  num_echoes,
const double  echo_spacing,
const double  T1,
const double  T2,
KS_DESCRIPTION  description 
)
420  {
421 
422  if (ks_plot_filefmt == KS_PLOT_OFF) {
423  return;
424  }
425 
426  FILE* fp;
427  char fname[1000]; /* Full filename of the json file */
428  char path[250]; /* Directory of json file */
429  char cmd[250];
430 
431 #ifdef PSD_HW
432  /* on MR-scanner */
433  sprintf(path, "/usr/g/mrraw/plot/%s/host/", ks_psdname);
434 #else
435  /* in Simulation */
436  sprintf(path, "./plot/host/");
437 #endif
438 
439  sprintf(cmd, "mkdir -p %s > /dev/null", path);
440  system(cmd);
441 
442  sprintf(fname, "%spsdplot_vrfa_%s_%s.json", path, ks_psdname, description);
443  fp = fopen(fname, "w");
444 
445  fprintf(fp, "{\n");
446  fprintf(fp, "\"psdname\": \"%s\",\n", ks_psdname);
447  fprintf(fp, "\"sequence\": \"%s\",\n", description);
448  fprintf(fp, "\"T1\": %0.3f,\n", T1);
449  fprintf(fp, "\"T2\": %0.3f,\n", T2);
450  fprintf(fp, "\"esp\": %0.3f,\n", echo_spacing);
451  fprintf(fp, "\"etl\": %d,\n", num_echoes);
452 
453  int idx;
454  fprintf(fp, "\"flip_angles\": [");
455  for (idx = 0; idx < num_echoes - 1; idx++) {
456  fprintf(fp, "%f, ", flip_angles[idx]);
457  }
458  fprintf(fp, "%f],\n",flip_angles[num_echoes-1]);
459 
460  fprintf(fp, "\"si_rel\": [");
461  for (idx = 0; idx < num_echoes - 1; idx++) {
462  fprintf(fp, "%f, ", si_rel[idx]);
463  }
464  fprintf(fp, "%f],\n",si_rel[num_echoes-1]);
465 
466  fprintf(fp, "\"si_norel\": [");
467  for (idx = 0; idx < num_echoes - 1; idx++) {
468  fprintf(fp, "%f, ", si_norel[idx]);
469  }
470  fprintf(fp, "%f],\n",si_norel[num_echoes-1]);
471 
472  fprintf(fp, "\"effTEs\": [");
473  for (idx = 0; idx < num_echoes - 1; idx++) {
474  fprintf(fp, "%f, ", effTEs[idx]);
475  }
476  fprintf(fp, "%f]\n",effTEs[num_echoes-1]);
477  fprintf(fp, "}\n");
478 
479  fflush(fp);
480  fclose(fp);
481 
482 } /* ks_print_epg_sim() */
Definition: KSFoundation.h:397
char ks_psdname[256]
Definition: GERequired.e:245
int ks_plot_filefmt
Definition: GERequired.e:272

◆ ks_predownload_plot_epg_sim()

void ks_predownload_plot_epg_sim ( KS_DESCRIPTION  description)

ADDTITLEHERE

ADDDESCHERE

Parameters
[in]descriptionADDTEXTHERE
Returns
void
487  {
488 
489  if (ks_plot_filefmt == KS_PLOT_OFF) {
490  return;
491  }
492 
493  char fname[1000]; /* Full filename of the json file */
494  char path[250]; /* Directory of json file */
495  char outputdir[250]; /* Where plots are saved */
496  char outputdir_uid[250]; /* rhkacq_uid based output directory (for automatic transfers) */
497 
498 #ifdef PSD_HW
499  /* on MR-scanner */
500  sprintf(path, "/usr/g/mrraw/plot/%s/host/", ks_psdname);
501  sprintf(outputdir, "/usr/g/mrraw/plot/%s/", ks_psdname);
502 
503  if (ks_plot_kstmp) {
504  sprintf(outputdir_uid, "/usr/g/mrraw/kstmp/%010d/plot/", rhkacq_uid);
505  }
506 #else
507  /* in Simulation */
508  sprintf(path, "./plot/host/");
509  sprintf(outputdir, "./plot/");
510 #endif
511 
512  sprintf(fname, "%spsdplot_vrfa_%s_%s.json", path, ks_psdname, description);
513 
514  char cmd[250];
515 
516 #ifdef PSD_HW
517  /* on MR-scanner */
518  if (ks_plot_kstmp) {
519  sprintf(cmd, "mkdir -p %s > /dev/null", outputdir_uid);
520  system(cmd);
521  }
522  char pythonpath[] = "/usr/local/bin/apython";
523  char psdplotpath[] = "/usr/local/bin/psdplot_vrfa.py";
524 #else
525  /* in Simulation */
526  char pythonpath[] = "apython";
527  char psdplotpath[] = "../KSFoundation/psdplot/psdplot_vrfa.py";
528 #endif
529  sprintf(cmd, "mkdir -p %s > /dev/null", path);
530  system(cmd);
531 
532  {
533  char cmd[1000];
534  char fname_plan[1000]; /* Full filename of the json file */
535  sprintf(fname_plan, "%spsdplot_%s_%s.json", path, ks_psdname, description);
536  sprintf(cmd, "%s %s %s %s "
537  "--outputdir %s &",
538  pythonpath, psdplotpath, fname_plan, fname,
539  outputdir);
540  ks_dbg("%s", cmd);
541  system(cmd);
542 #ifdef PSD_HW
543  /* on MR-scanner */
544  if (ks_plot_kstmp) {
545  sprintf(outputdir_uid, "/usr/g/mrraw/kstmp/%010d/plot/", rhkacq_uid);
546  sprintf(cmd, "cp %s%s_%s.html %s",
547  outputdir, ks_psdname, description,
548  outputdir_uid);
549  system(cmd);
550  sprintf(cmd, "cp %s %s > /dev/null", fname, outputdir_uid);
551  system(cmd);
552  }
553 #endif
554  }
555 (void)outputdir_uid;
556 
557 } /* ks_predownload_plot_epg_sim() */
Definition: KSFoundation.h:397
char ks_psdname[256]
Definition: GERequired.e:245
int ks_plot_filefmt
Definition: GERequired.e:272
int rhkacq_uid
int ks_plot_kstmp
Definition: GERequired.e:273
STATUS STATUS ks_dbg(const char *format,...) __attribute__((format(printf
Common debug message function for HOST and TGT

◆ ksepg_calc_effTE()

STATUS ksepg_calc_effTE ( const float *  flip_angles,
double *  effTEs,
int  num_echoes,
double  echo_spacing,
double  T1,
double  T2,
KS_DESCRIPTION  desc 
)

Computes the effective echo time at each echo of a classic FSE train

Parameters
[in]flip_anglesRefocusing flip angles
[out]effTEsEffective echo time for each echo
[in]num_echoesNumber of echoes in the train
[in]echo_spacingEcho spacing for the FSE train
[in]T1T_1 value for the tissue of interest
[in]T2T_2 value for the tissue of interest
[in]descDescription for printing to file
Return values
STATUSSUCCESS or FAILURE
562  {
563 
564  if (!flip_angles || !effTEs) { KS_RAISE(FAILURE); }
565 
566  STATUS status;
567  int i;
568 
569  double *flip_angles_radians = (double *)alloca(num_echoes * sizeof(double));
570  for (i=0; i<num_echoes; i++){
571  flip_angles_radians[i] = (double)flip_angles[i]*PI/180;
572  }
573 
574  /* calc signal intensites with and without relaxation */
575  double *si_rel = (double *)alloca(num_echoes * sizeof(double));
576  status = ksepg_get_intensities_std(flip_angles_radians, si_rel, num_echoes, echo_spacing, T1, T2);
577  KS_RAISE(status);
578 
579  ks_dbg("intensity (esp=%.1f, T1=%.0f, T2=%.0f): %.2f -> %.2f -> %.2f",
580  echo_spacing, T1, T2, si_rel[1], si_rel[num_echoes/2], si_rel[num_echoes-1]);
581 
582  double *si_norel = (double *)alloca(num_echoes * sizeof(double));
583  status = ksepg_get_intensities_std(flip_angles_radians, si_norel, num_echoes, 0, 1, 1);
584  KS_RAISE(status);
585 
586  /* calculate relaxation term (r) and effTEs */
587  int echo;
588  for (echo=0; echo < num_echoes; echo++) {
589 
590  if (si_rel[echo]>0 && si_norel[echo]>=si_rel[echo]) {
591 
592  double r = si_rel[echo] / si_norel[echo];
593  effTEs[echo] = -T2*log(r);
594  } else {
595 
596  /* Failed to calculate, use a placeholder instead */
597  effTEs[echo] = (echo+1)*echo_spacing;
598  }
599  }
600 
601  ks_print_epg_sim(flip_angles, si_rel, si_norel, effTEs, num_echoes, echo_spacing, T1, T2, description);
602 
603  /* Check for "slice profile" */
604  const double rel_beg = si_rel[1];
605  const double rel_mid = si_rel[num_echoes/2];
606  const double rel_end = si_rel[num_echoes-1];
607 
608 
609  for (i=0; i<num_echoes; i++){
610  flip_angles_radians[i] *= 0.5;
611  }
612 
613  status = ksepg_get_intensities_std(flip_angles_radians, si_rel, num_echoes, 0, 1, 1);
614  KS_RAISE(status);
615  ks_dbg("intensity half norel loss: %.2f -> %.2f -> %.2f",
616  si_rel[1]/si_norel[1], si_rel[num_echoes/2]/si_norel[num_echoes/2], si_rel[num_echoes-1]/si_norel[num_echoes-1]);
617 
618  status = ksepg_get_intensities_std(flip_angles_radians, si_rel, num_echoes, echo_spacing, T1, T2);
619  KS_RAISE(status);
620 
621  ks_dbg("intensity half rel loss: %.2f -> %.2f -> %.2f",
622  si_rel[1]/rel_beg, si_rel[num_echoes/2]/rel_mid, si_rel[num_echoes-1]/rel_end);
623 
624  return SUCCESS;
625 
626 } /* ksepg_calc_effTE() */
void ks_print_epg_sim(const float *flip_angles, const double *si_rel, const double *si_norel, const double *effTEs, const int num_echoes, const double echo_spacing, const double T1, const double T2, KS_DESCRIPTION description)
Definition: ksepg.cc:419
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS STATUS ks_dbg(const char *format,...) __attribute__((format(printf
Common debug message function for HOST and TGT
STATUS ksepg_get_intensities_std(const double *flip_angles, double *signal_intensities, int num_echoes, double echo_spacing, double T1, double T2)
Simulate a classic FSE train with EPG to compute the signal intensities
Definition: ksepg.cc:225

◆ ksepg_max_angle()

double ksepg_max_angle ( double *  flip_angles,
int  num_echoes 
)

Returns the maximum refocusing angle

Parameters
[in]flip_anglesRefocusing flip angles
[in]num_echoesNumber of echoes in the train
Returns
double The maximum refocusing flip angle
631  {
632 
633  if (!flip_angles) { return 0; }
634 
635  double max_angle = 0;
636  int i;
637  for (i=0; i<num_echoes; ++i) {
638  max_angle = flip_angles[i] > max_angle ? flip_angles[i] : max_angle;
639  }
640 
641  return max_angle;
642 
643 } /* ksepg_max_angle() */

◆ ksepg_optimize_constant()

STATUS ksepg_optimize_constant ( double *  intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
const KSEPG_STATE  starting_state 
)

ADDTITLEHERE

Parameters
intensityADDTEXTHERE
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
[in]starting_stateADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
652  {
653 
654  if (!flip_angles) { return KS_THROW("NULL input"); }
655 
656  double low_tgt = 0;
657  double hi_tgt = 1;
658 
659  STATUS status = FAILURE;
660  int i;
661  for (i=0; i<10; ++i) {
662  double tgt = (hi_tgt + low_tgt)/2;
663 
664  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
665  status = ksepg_track_intensity_curve(flip_angles, num_echoes, state, tgt, NULL, echo_spacing, T1, T2);
666  ksepg_destruct_state(&state);
667 
668  if (status == SUCCESS && ksepg_max_angle(flip_angles, num_echoes) < max_flip) {
669  low_tgt = tgt;
670  } else {
671  hi_tgt = tgt;
672  }
673  }
674 
675  if (low_tgt > 0) {
676  if (intensity) {
677  *intensity = low_tgt;
678  }
679 
680  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
681  status = ksepg_track_intensity_curve(flip_angles, num_echoes, state, low_tgt, NULL, echo_spacing, T1, T2);
682  ksepg_destruct_state(&state);
683  KS_RAISE(status);
684 
685  return SUCCESS;
686  }
687 
688  return KS_THROW("Failed");
689 
690 } /* ksepg_optimize_constant() */
STATUS ksepg_track_intensity_curve(double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
Track the requested intensity curve with a custom starting EPG state
Definition: ksepg.cc:316
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
KSEPG_STATE ksepg_duplicate_state(const KSEPG_STATE *state)
Duplicate an EPG&#39;s state
Definition: ksepg.cc:66
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_constant_std()

STATUS ksepg_optimize_constant_std ( double *  intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2 
)

Find the maximum constant intensity that can be mantained

698  {
699 
700  const int state_size = 2*num_echoes + 1;
701 
702  /* initialize the state to the value after the excitation */
703  KSEPG_STATE state = ksepg_create_state(state_size);
704  state.data[0] = 1;
705  state.data[1] = 1;
706 
707  return ksepg_optimize_constant(intensity,
708  flip_angles, num_echoes,
709  max_flip,
710  echo_spacing, T1, T2,
711  state);
712 
713 } /* ksepg_optimize_constant_std() */
double * data
Definition: ksepg.h:43
STATUS ksepg_optimize_constant(double *intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
ADDTITLEHERE
Definition: ksepg.cc:648
Extended phase graph state
Definition: ksepg.h:41
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_constant_long()

STATUS ksepg_optimize_constant_long ( double *  intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
intensityADDTEXTHERE
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
721  {
722 
723  const int state_size = 2*num_echoes + 3;
724 
725  KS_MAT3x3 rot;
726  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
727 
728  /* initialize the state to the value after the excitation */
729  KSEPG_STATE state = ksepg_create_state(state_size);
730  state.data[0] = 1;
731  state.data[1] = 1;
732 
733  /* apply a first refocusing of 90 degrees */
734  ksepg_compute_rotation(&rot, PI/2);
735  ksepg_next_echo(&state, &rot, rel);
736 
737  return ksepg_optimize_constant(intensity,
738  flip_angles, num_echoes,
739  max_flip,
740  echo_spacing, T1, T2,
741  state);
742 
743 } /* ksepg_optimize_constant_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
STATUS ksepg_optimize_constant(double *intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
ADDTITLEHERE
Definition: ksepg.cc:648
Extended phase graph state
Definition: ksepg.h:41
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_generate_intensity_triangle_impl()

STATUS ksepg_generate_intensity_triangle_impl ( double *  target_intensities,
int  num_echoes,
double  center_position,
double  min_intensity,
double  max_intensity,
double  half_size 
)

Circular VFA modulation

The aim is to modulate the FA so that the intensity is the same at the start and the end of the train. There are two possible strategies:

  • Slanted triangle, where the peak is where the center echo is intented to be and both sides decrease with different slopes towards the same intensity.
  • Circular shifted triangle, where a symmetric triangle is circulally shifted in order to match the peak with the center echo. There should be limitations on where the center echo can be dispaced from the middle. Maybe displacements greater than num_echoes/4 should not be allowed. The intensity at the center echoes is an input. The intensity at the valleys of the triangle is optimized. In general we want the highest intensity possible up to matching the center echo's
Parameters
target_intensitiesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]center_positionADDTEXTHERE
[in]min_intensityADDTEXTHERE
[in]max_intensityADDTEXTHERE
[in]half_sizeADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
749  {
750  if (!target_intensities) {
751  return KS_THROW("Target_intensities is NULL");
752  }
753 
754  if (center_position < 0 || center_position >= num_echoes) {
755  return KS_THROW("center_echo (%f) must be in the interval [0, %d]", center_position, num_echoes-1);
756  }
757 
758  if (min_intensity < 0 || min_intensity >= 1) {
759  return KS_THROW("min_intensity (%f) must be in the interval [0, 1)", min_intensity);
760  }
761 
762  if (max_intensity <= min_intensity || max_intensity >= 1) {
763  return KS_THROW("max_intensity (%f) must be in the interval [%f, 1)", max_intensity, min_intensity);
764  }
765 
766  const double min_half_size = (num_echoes - 1.0)/2.0;
767  if (half_size < min_half_size) {
768  return KS_THROW("half_size (%f) must be greater than half of num_echoes %f", half_size, min_half_size);
769  }
770 
771  int i;
772 
773  /* Generate the pattern */
774  double max_unscaled = 0, min_unscaled = 1;
775  for (i=0; i<num_echoes; ++i) {
776  double echo_pos = i - center_position;
777  double unscaled = fabs(1 - fabs(echo_pos)/half_size);
778 
779  max_unscaled = FMax(2, unscaled, max_unscaled);
780  min_unscaled = FMin(2, unscaled, min_unscaled);
781  target_intensities[i] = unscaled;
782  }
783 
784  /* Scale the pattern to min_intensity/max_intensity */
785  for (i=0; i<num_echoes; ++i) {
786  target_intensities[i] = min_intensity + (target_intensities[i] - min_unscaled)*(max_intensity - min_intensity) / (max_unscaled - min_unscaled);
787  }
788 
789  return SUCCESS;
790 
791 } /* ksepg_generate_intensity_triangle_impl() */
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_generate_intensity_periodic_triangle()

STATUS ksepg_generate_intensity_periodic_triangle ( double *  target_intensities,
int  num_echoes,
double  center_position,
double  min_intensity,
double  max_intensity 
)

Function used to generate bounded intensity curves

798  {
799  const double half_size = (num_echoes - 1.0)/2.0;
800 
801  return ksepg_generate_intensity_triangle_impl(target_intensities, num_echoes,
802  center_position, min_intensity, max_intensity, half_size);
803 
804 } /* ksepg_generate_intensity_periodic_triangle() */
STATUS ksepg_generate_intensity_triangle_impl(double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity, double half_size)
Circular VFA modulation
Definition: ksepg.cc:748

◆ ksepg_generate_intensity_cropped_triangle()

STATUS ksepg_generate_intensity_cropped_triangle ( double *  target_intensities,
int  num_echoes,
double  center_position,
double  min_intensity,
double  max_intensity 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
target_intensitiesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]center_positionADDTEXTHERE
[in]min_intensityADDTEXTHERE
[in]max_intensityADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
811  {
812  const double half_size = FMax(2, center_position, num_echoes - 1 - center_position);
813 
814  return ksepg_generate_intensity_triangle_impl(target_intensities, num_echoes,
815  center_position, min_intensity, max_intensity, half_size);
816 
817 } /* ksepg_generate_intensity_cropped_triangle() */
STATUS ksepg_generate_intensity_triangle_impl(double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity, double half_size)
Circular VFA modulation
Definition: ksepg.cc:748

◆ ksepg_generate_intensity_ramp()

STATUS ksepg_generate_intensity_ramp ( double *  target_intensities,
int  num_echoes,
double  center_position,
double  min_intensity,
double  max_intensity 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
target_intensitiesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]center_positionADDTEXTHERE
[in]min_intensityADDTEXTHERE
[in]max_intensityADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
823  {
824 
825  int i = 0;
826  for (; i < center_position+1; ++i) {
827  target_intensities[i] = max_intensity;
828  }
829  const double hedge = i-1;
830  for (; i<num_echoes; ++i) {
831  target_intensities[i] =
832  max_intensity * (num_echoes-1 - i)/(num_echoes-1 - hedge) +
833  min_intensity * (i - hedge)/(num_echoes-1 - hedge);
834  }
835 
836  return SUCCESS;
837 
838 } /* ksepg_generate_intensity_ramp() */

◆ ksepg_generate_intensity_linear()

STATUS ksepg_generate_intensity_linear ( double *  target_intensities,
int  num_echoes,
double  center_position,
double  min_intensity,
double  max_intensity 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
target_intensitiesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]center_positionADDTEXTHERE
[in]min_intensityADDTEXTHERE
[in]max_intensityADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
844  {
845 
846  (void)center_position;
847  double slope = (min_intensity-max_intensity)/(num_echoes-1);
848  int i = 0;
849  for (; i<num_echoes; ++i) {
850  target_intensities[i] = max_intensity + i*slope;
851  }
852 
853  return SUCCESS;
854 
855 } /* ksepg_generate_intensity_linear() */

◆ ksepg_track_bounded_curve()

STATUS ksepg_track_bounded_curve ( double *  flip_angles,
double *  target_intensities,
int  num_echoes,
double  min_intensity,
double  max_intensity,
double  echo_spacing,
double  T1,
double  T2,
double  center_position,
STATUS(*)(double *, int, double, double, double)  generate_bounded_curve,
const KSEPG_STATE  starting_state 
)
865  {
866  STATUS s;
867  s = generate_bounded_curve(target_intensities, num_echoes, center_position, min_intensity, max_intensity);
868  KS_RAISE(s);
869 
870  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
871  s = ksepg_track_intensity_curve(flip_angles, num_echoes, state,
872  1.0, target_intensities,
873  echo_spacing, T1, T2);
874  ksepg_destruct_state(&state);
875 
876  return s;
877 
878 } /* ksepg_track_bounded_curve() */
STATUS ksepg_track_intensity_curve(double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
Track the requested intensity curve with a custom starting EPG state
Definition: ksepg.cc:316
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
KSEPG_STATE ksepg_duplicate_state(const KSEPG_STATE *state)
Duplicate an EPG&#39;s state
Definition: ksepg.cc:66
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57

◆ ksepg_optimize_bounded_curve()

STATUS ksepg_optimize_bounded_curve ( double *  min_intensity,
double *  max_intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
double  center_position,
STATUS(*)(double *, int, double, double, double)  generate_bounded_curve,
const KSEPG_STATE  starting_state 
)
889  {
890 
891  if (!flip_angles) { return KS_THROW("No flip-angle or state array found"); }
892 
893  STATUS status = FAILURE;
894  double opt_max_intensity = 0;
895  double opt_min_intensity = 0;
896 
897  double *target_intensities;
898  target_intensities = (double*)alloca(num_echoes * sizeof(double));
899  double opt_objective = 0.0;
900 
901  double alpha;
902  const double outer_loop_step = 0.1;
903  int i;
904  const int inner_loop_size = 20;
905 
906  if (outer_loop_step < 0.01 || outer_loop_step > 0.5) {
907  return KS_THROW("outer_loop_step (%f) is out of bounds", outer_loop_step);
908  }
909 
910  for (alpha=outer_loop_step; alpha<1.0; alpha += outer_loop_step) {
911 
912  double max_high = 1;
913  double max_low = 0;
914 
915  for (i=0; i<inner_loop_size; i++) {
916 
917  const double loop_max_intensity = (max_high + max_low)/2;
918  const double loop_min_intensity = alpha * loop_max_intensity;
919 
920  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
921  loop_min_intensity, loop_max_intensity,
922  echo_spacing, T1, T2,
923  center_position,
924  generate_bounded_curve,
925  starting_state);
926 
927  if (status != SUCCESS || ksepg_max_angle(flip_angles, num_echoes) > max_flip) {
928  max_high = loop_max_intensity;
929  continue;
930  }
931 
932  max_low = loop_max_intensity;
933 
934  const double objective = pow(loop_max_intensity, 4) * loop_min_intensity;
935  if (opt_objective >= objective) {
936  continue;
937  }
938 
939  opt_objective = objective;
940  opt_max_intensity = loop_max_intensity;
941  opt_min_intensity = loop_min_intensity;
942  }
943  }
944 
945  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
946  opt_min_intensity, opt_max_intensity,
947  echo_spacing, T1, T2,
948  center_position,
949  generate_bounded_curve,
950  starting_state);
951  KS_RAISE(status);
952 
953  if (min_intensity) { *min_intensity = opt_min_intensity; };
954  if (max_intensity) { *max_intensity = opt_max_intensity; };
955 
956  return SUCCESS;
957 
958 } /* ksepg_optimize_bounded_curve */
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
STATUS ksepg_track_bounded_curve(double *flip_angles, double *target_intensities, int num_echoes, double min_intensity, double max_intensity, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:860
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_bounded_curve_std()

STATUS ksepg_optimize_bounded_curve_std ( double *  min_intensity,
double *  max_intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
double  center_position,
STATUS(*)(double *, int, double, double, double)  generate_bounded_curve 
)

Optimize a bounded intensity curve so that it maximizes the center position's intensity

Optimize the target intensity curve modeled as a bounded curve in order to maximise the intensity at the echo corresponding to the center of the k-space. A bounded curve is parameterized by the maximum and minim intensities over all echoes.

968  {
969  const int state_size = 2*num_echoes + 1;
970  KSEPG_STATE state = ksepg_create_state(state_size);
971  state.data[0] = 1;
972  state.data[1] = 1;
973 
974  STATUS s = ksepg_optimize_bounded_curve(min_intensity, max_intensity,
975  flip_angles, num_echoes,
976  max_flip,
977  echo_spacing, T1, T2,
978  center_position,
979  generate_bounded_curve,
980  state);
981  ksepg_destruct_state(&state);
982 
983  KS_RAISE(s);
984 
985  return SUCCESS;
986 
987 } /* ksepg_optimize_bounded_curve_std() */
double * data
Definition: ksepg.h:43
STATUS ksepg_optimize_bounded_curve(double *min_intensity, double *max_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:883
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_bounded_curve_long()

STATUS ksepg_optimize_bounded_curve_long ( double *  min_intensity,
double *  max_intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
double  center_position,
STATUS(*)(double *, int, double, double, double)  generate_bounded_curve 
)

ADDTITLEHERE

997  {
998  const int state_size = 2*num_echoes + 3;
999 
1000  KS_MAT3x3 rot;
1001  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
1002 
1003  KSEPG_STATE state = ksepg_create_state(state_size);
1004  state.data[0] = 1;
1005  state.data[1] = 1;
1006 
1007  /* apply a first refocusing of 90 degrees */
1008  ksepg_compute_rotation(&rot, PI/2);
1009  ksepg_next_echo(&state, &rot, rel);
1010 
1011  STATUS s = ksepg_optimize_bounded_curve(min_intensity, max_intensity,
1012  flip_angles, num_echoes,
1013  max_flip,
1014  echo_spacing, T1, T2,
1015  center_position,
1016  generate_bounded_curve,
1017  state);
1018  ksepg_destruct_state(&state);
1019 
1020  KS_RAISE(s);
1021 
1022  return SUCCESS;
1023 
1024 } /* ksepg_optimize_bounded_curve_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
STATUS ksepg_optimize_bounded_curve(double *min_intensity, double *max_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:883
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_rampdown()

STATUS ksepg_optimize_rampdown ( double *  end_intensity,
double  start_intensity,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
const KSEPG_STATE  starting_state 
)

ADDTITLEHERE

1033  {
1034 
1035  if (!flip_angles) { return KS_THROW("No flip-angle or state array found"); }
1036 
1037  STATUS status = FAILURE;
1038  *end_intensity = 1;
1039 
1040  double *target_intensities;
1041  target_intensities = (double *)alloca(num_echoes * sizeof(double));
1042 
1043  int i;
1044  const int loop_size = 10;
1045 
1046  double end_high = 1;
1047  double end_low = 0;
1048  for (i=0; i<loop_size; i++) {
1049 
1050  const double loop_end_intensity = (end_high + end_low)/2;
1051 
1052  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1053  loop_end_intensity, start_intensity,
1054  echo_spacing, T1, T2,
1055  0,
1057  starting_state);
1058 
1059  if (status != SUCCESS || ksepg_max_angle(flip_angles, num_echoes) > max_flip) {
1060  end_high = loop_end_intensity;
1061  continue;
1062  }
1063 
1064  end_low = loop_end_intensity;
1065 
1066  *end_intensity = loop_end_intensity;
1067  }
1068 
1069  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1070  *end_intensity, start_intensity,
1071  echo_spacing, T1, T2,
1072  0,
1074  starting_state);
1075  KS_RAISE(status);
1076 
1077  return SUCCESS;
1078 
1079 } /* ksepg_optimize_rampdown() */
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
STATUS ksepg_track_bounded_curve(double *flip_angles, double *target_intensities, int num_echoes, double min_intensity, double max_intensity, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:860
STATUS ksepg_generate_intensity_linear(double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
ADDTITLEHERE
Definition: ksepg.cc:843
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_half_intensity()

STATUS ksepg_half_intensity ( double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
KSEPG_TAIL  tail_type 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
[in]tail_typeADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1088  {
1089 
1090  if (!flip_angles) { return KS_THROW("NULL flip-angle array"); }
1091 
1092  const int state_size = 2*num_echoes + 1;
1093 
1094  /* initialize the state to the value after the excitation */
1095  KSEPG_STATE state = ksepg_create_state(state_size);
1096  state.data[0] = 1;
1097  state.data[1] = 1;
1098 
1099  KS_MAT3x3 rot;
1100  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
1101 
1102  const double intensity = 0.5;
1103 
1104  int i;
1105  for (i=0; i<num_echoes; ++i) {
1106  /* advance the state to before the refocusing */
1107  ksepg_dephase(&state, rel);
1108 
1109  const double flip = ksepg_track_step(state.data[3], state.data[4], state.data[5], intensity, rel);
1110 
1111  if (isNaN(flip) || flip > max_flip) {
1112  break;
1113  }
1114 
1115  flip_angles[i] = flip;
1116 
1117  /* advance the state to the next echo */
1118  ksepg_compute_rotation(&rot, flip);
1119  ksepg_refocus(&state, &rot);
1120  ksepg_dephase(&state, rel);
1121  }
1122 
1123  switch (tail_type) {
1124  case KSEPG_RAMPDOWN:
1125  {
1126  return KS_THROW("Not implemented yet");
1127  }
1128  default:
1129  {
1130  for (; i<num_echoes; ++i) {
1131  flip_angles[i] = max_flip;
1132  }
1133  }
1134  }
1135 
1136  return SUCCESS;
1137 
1138 } /* ksepg_half_intensity() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
void ksepg_refocus(KSEPG_STATE *state, KS_MAT3x3 *rot)
Apply a refocusing operator to an EPG state
Definition: ksepg.cc:162
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
Extended phase graph state
Definition: ksepg.h:41
void ksepg_dephase(KSEPG_STATE *state, KSEPG_RELAXATION rel_op)
Apply a dephasing step and a relaxation operator to an EPG state
Definition: ksepg.cc:82
Definition: ksepg.h:570
int isNaN(float a)
Definition: KSFoundation_common.c:58
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
double ksepg_track_step(double Fp, double Fm, double Z, double target_Fm, KSEPG_RELAXATION rel_op)
Attempt to track a target intensity
Definition: ksepg.cc:303

◆ ksepg_optimize_expdown()

STATUS ksepg_optimize_expdown ( double *  flip_angles,
int  num_echoes,
double  max_flip,
double  echo_spacing,
double  T1,
double  T2,
const KSEPG_STATE  starting_state 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
[in]starting_stateADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1146  {
1147 
1148  if (!flip_angles) { return KS_THROW("NULL flip-angle array"); }
1149 
1150  STATUS status;
1151  const double start_intensity = starting_state.data[1];
1152 
1153  double alpha_high = 0.1;
1154  double alpha_low = -0.1;
1155 
1156  double *target_intensity = (double*)alloca(num_echoes * sizeof(double));
1157 
1158  double alpha = alpha_low;
1159  int i = 0;
1160  int echo;
1161  for (; i<10; ++i) {
1162 
1163  /* Generate the target intensity curve */
1164  for (echo = 0; echo<num_echoes; ++echo) {
1165  target_intensity[echo] = start_intensity*exp(alpha*(echo + 0.5)*echo_spacing);
1166  }
1167 
1168  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
1169  status = ksepg_track_intensity_curve(flip_angles, num_echoes,
1170  state,
1171  1, target_intensity,
1172  echo_spacing, T1, T2);
1173  if (status != SUCCESS && ksepg_max_angle(flip_angles, num_echoes) < max_flip) {
1174  alpha_high = alpha;
1175  continue;
1176  }
1177 
1178  alpha_low = alpha;
1179  alpha = (alpha_high + alpha_low)/2;
1180  }
1181 
1182  /* Rerun the EPG to fill the correct flip angles */
1183  for (echo=0; echo<num_echoes; ++echo) {
1184  target_intensity[echo] = start_intensity*exp(alpha_low*(echo + 0.5)*echo_spacing);
1185  }
1186 
1187  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
1188  status = ksepg_track_intensity_curve(flip_angles, num_echoes,
1189  state,
1190  1, target_intensity,
1191  echo_spacing, T1, T2);
1192  KS_RAISE(status);
1193 
1194  return SUCCESS;
1195 
1196 } /* ksepg_optimize_expdown() */
double * data
Definition: ksepg.h:43
STATUS ksepg_track_intensity_curve(double *flip_angles, int num_echoes, KSEPG_STATE state, double scaling_factor, const double *target_curve, double echo_spacing, double T1, double T2)
Track the requested intensity curve with a custom starting EPG state
Definition: ksepg.cc:316
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
KSEPG_STATE ksepg_duplicate_state(const KSEPG_STATE *state)
Duplicate an EPG&#39;s state
Definition: ksepg.cc:66
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_half_exponential()

STATUS ksepg_optimize_half_exponential ( double *  flip_angles,
int  num_echoes,
double  max_flip 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1202  {
1203 
1204  if (!flip_angles) { return KS_THROW("NULL flip-angle array"); }
1205 
1206  const int state_size = 2*num_echoes + 1;
1207 
1208  /* initialize the state to the value after the excitation */
1209  KSEPG_STATE state = ksepg_create_state(state_size);
1210  state.data[0] = 1;
1211  state.data[1] = 1;
1212 
1213  KS_MAT3x3 rot;
1215 
1216  /* apply a first refocusing of 90 degrees */
1217  flip_angles[0] = PI/2;
1218  ksepg_compute_rotation(&rot, flip_angles[0]);
1219  ksepg_next_echo(&state, &rot, rel);
1220 
1221  STATUS s = ksepg_optimize_expdown(flip_angles+1, num_echoes-1,
1222  max_flip,
1223  0, 1, 1,
1224  state);
1225 
1226  ksepg_destruct_state(&state);
1227 
1228  KS_RAISE(s);
1229 
1230  return SUCCESS;
1231 
1232 } /* ksepg_optimize_half_exponential() */
double * data
Definition: ksepg.h:43
STATUS ksepg_optimize_expdown(double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
ADDTITLEHERE
Definition: ksepg.cc:1143
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_half_free()

STATUS ksepg_optimize_half_free ( double *  flip_angles,
int  num_echoes,
double  max_flip 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1238  {
1239 
1240  if (!flip_angles) { return KS_THROW("NULL flip-angle array"); }
1241 
1242  const int state_size = 2*num_echoes + 1;
1243 
1244  /* initialize the state to the value after the excitation */
1245  KSEPG_STATE state = ksepg_create_state(state_size);
1246  state.data[0] = 1;
1247  state.data[1] = 1;
1248 
1249  KS_MAT3x3 rot;
1251 
1252  /* apply a first refocusing of 90 degrees */
1253  flip_angles[0] = PI/2;
1254  ksepg_compute_rotation(&rot, flip_angles[0]);
1255  ksepg_next_echo(&state, &rot, rel);
1256 
1257  const double start_intensity = state.data[1];
1258  double end_intensity;
1259 
1260  STATUS s = ksepg_optimize_rampdown(&end_intensity, start_intensity,
1261  flip_angles+1, num_echoes-1,
1262  max_flip,
1263  0, 1, 1,
1264  state);
1265 
1266  ksepg_destruct_state(&state);
1267 
1268  KS_RAISE(s);
1269 
1270  return SUCCESS;
1271 
1272 } /* ksepg_optimize_half_free() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
STATUS ksepg_optimize_rampdown(double *end_intensity, double start_intensity, double *flip_angles, int num_echoes, double max_flip, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
ADDTITLEHERE
Definition: ksepg.cc:1029
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_linear_free()

STATUS ksepg_optimize_linear_free ( double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2,
const KSEPG_STATE  starting_state 
)

Search for a linear relaxation-free intensity curve that

maximize the concave objective function:

f_obj = max_intensity * min_intensity^min_intensity_weight

where both max_intensity and min_intensity are calculated by taking into accout the relexation effect.

Parameters
[out]flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
[in]starting_stateADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1280  {
1281 
1282 
1283  if (!flip_angles) {
1284  return KS_THROW("No flip-angle or state array found");
1285  }
1286  if (min_intensity_weight < 0) {
1287  return KS_THROW("Weight for the minimum intensity must be non-negative");
1288  }
1289 
1290  STATUS status = FAILURE;
1291  double opt_max_intensity = 0;
1292  double opt_min_intensity = 0;
1293 
1294  double *target_intensities;
1295  target_intensities = (double*)alloca(num_echoes * sizeof(double));
1296  double opt_objective = 0.0;
1297 
1298  double max_intensity;
1299  const double outer_loop_step = 0.1;
1300  int i;
1301  const int inner_loop_size = 10;
1302 
1303  if (outer_loop_step < 0.01 || outer_loop_step > 0.5) {
1304  return KS_THROW("outer_loop_step (%f) is out of bounds", outer_loop_step);
1305  }
1306 
1307  for (max_intensity=outer_loop_step; max_intensity<1.0; max_intensity += outer_loop_step) {
1308 
1309  double min_high = 1;
1310  double min_low = max_intensity;
1311 
1312  for (i=0; i<inner_loop_size; i++) {
1313  const double min_intensity = (min_high + min_low)/2;
1314 
1315  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1316  min_intensity, max_intensity,
1317  0, 1, 1, /* relaxation free */
1318  0, /* unused */
1320  starting_state);
1321 
1322  if (status != SUCCESS || ksepg_max_angle(flip_angles, num_echoes) > max_flip) {
1323  min_high = min_intensity;
1324  continue;
1325  }
1326 
1327  min_low = min_intensity;
1328 
1329  /* Calculate the objective by */
1330  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
1331  status = ksepg_get_intensities(flip_angles, num_echoes,
1332  state,
1333  target_intensities,
1334  echo_spacing, T1, T2);
1335  ksepg_destruct_state(&state);
1336  KS_RAISE(status);
1337 
1338  const double objective =
1339  target_intensities[0] * pow(target_intensities[num_echoes-1], min_intensity_weight);
1340  if (opt_objective > objective) {
1341  continue;
1342  }
1343 
1344  opt_objective = objective;
1345  opt_max_intensity = max_intensity;
1346  opt_min_intensity = min_intensity;
1347  }
1348  }
1349 
1350  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1351  opt_min_intensity, opt_max_intensity,
1352  0, 1, 1, /* relaxation free */
1353  0, /* unused */
1355  starting_state);
1356  KS_RAISE(status);
1357 
1358  return SUCCESS;
1359 
1360 } /* ksepg_optimize_linear_free() */
STATUS ksepg_get_intensities(const double *flip_angles, int num_echoes, KSEPG_STATE state, double *signal_intensities, double echo_spacing, double T1, double T2)
ADDTITLEHERE
Definition: ksepg.cc:186
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
KSEPG_STATE ksepg_duplicate_state(const KSEPG_STATE *state)
Duplicate an EPG&#39;s state
Definition: ksepg.cc:66
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
STATUS ksepg_track_bounded_curve(double *flip_angles, double *target_intensities, int num_echoes, double min_intensity, double max_intensity, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:860
STATUS ksepg_generate_intensity_linear(double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
ADDTITLEHERE
Definition: ksepg.cc:843
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_linear_free_std()

STATUS ksepg_optimize_linear_free_std ( double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1367  {
1368  const int state_size = 2*num_echoes + 1;
1369  KSEPG_STATE state = ksepg_create_state(state_size);
1370  state.data[0] = 1;
1371  state.data[1] = 1;
1372 
1373  STATUS s = ksepg_optimize_linear_free(flip_angles, num_echoes,
1374  max_flip, min_intensity_weight,
1375  echo_spacing, T1, T2,
1376  state);
1377  ksepg_destruct_state(&state);
1378 
1379  KS_RAISE(s);
1380 
1381  return SUCCESS;
1382 
1383 } /* ksepg_optimize_linear_free_std() */
double * data
Definition: ksepg.h:43
STATUS ksepg_optimize_linear_free(double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
Search for a linear relaxation-free intensity curve that
Definition: ksepg.cc:1277
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_linear_free_long()

STATUS ksepg_optimize_linear_free_long ( double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1390  {
1391  const int state_size = 2*num_echoes + 3;
1392 
1393  KS_MAT3x3 rot;
1394  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
1395 
1396  KSEPG_STATE state = ksepg_create_state(state_size);
1397  state.data[0] = 1;
1398  state.data[1] = 1;
1399 
1400  /* apply a first refocusing of 90 degrees */
1401  ksepg_compute_rotation(&rot, PI/2);
1402  ksepg_next_echo(&state, &rot, rel);
1403 
1404  STATUS s = ksepg_optimize_linear_free(flip_angles, num_echoes,
1405  max_flip, min_intensity_weight,
1406  echo_spacing, T1, T2,
1407  state);
1408  ksepg_destruct_state(&state);
1409 
1410  KS_RAISE(s);
1411 
1412  return SUCCESS;
1413 
1414 } /* ksepg_optimize_linear_free_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
STATUS ksepg_optimize_linear_free(double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
Search for a linear relaxation-free intensity curve that
Definition: ksepg.cc:1277
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_linear_free_center_echo()

STATUS ksepg_optimize_linear_free_center_echo ( int *  _center_echo,
int  target_eff_TE,
int  linear_sweep_center_echo,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2,
const KSEPG_STATE  starting_state 
)

Joint VFA modulation and center echo selection from TE

The objective is to place the center and modulate the FA so that we get a certain effective TE.

Start placing the center in the middle, target an VFA that would yield an intensity that matches the SE intensity at the requested TE for certain T1/T2 values. Calculate the effective TE. Move the center to the left or right depending if the effective TE is higher or lower than the target TE respectively. Regenerate the VFA modulation with the same target for the center echo.

Does this converge?

Parameters
_center_echoADDTEXTHERE
[in]target_eff_TEADDTEXTHERE
[in]linear_sweep_center_echoADDTEXTHERE
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
[in]starting_stateADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1424  {
1425 
1426 
1427  if (!flip_angles) {
1428  return KS_THROW("No flip-angle or state array found");
1429  }
1430  if (min_intensity_weight < 0) {
1431  return KS_THROW("Weight for the minimum intensity must be non-negative");
1432  }
1433 
1434  STATUS status = FAILURE;
1435  double opt_max_intensity = 0;
1436  double opt_min_intensity = 0;
1437  int opt_center_echo = 0;
1438 
1439  double *target_intensities;
1440  target_intensities = (double*)alloca(num_echoes * sizeof(double));
1441  double *relax_intensities;
1442  relax_intensities = (double*)alloca(num_echoes * sizeof(double));
1443  double opt_objective = 0.0;
1444 
1445  double max_intensity;
1446  const double outer_loop_step = 0.1;
1447  int i;
1448  const int inner_loop_size = 20;
1449 
1450  if (outer_loop_step < 0.01 || outer_loop_step > 0.5) {
1451  return KS_THROW("outer_loop_step (%f) is out of bounds", outer_loop_step);
1452  }
1453 
1454  const double normalizing_factor = IMin(2, linear_sweep_center_echo, num_echoes - linear_sweep_center_echo -1);
1455 
1456  for (max_intensity=outer_loop_step; max_intensity<1.0; max_intensity += outer_loop_step) {
1457 
1458  double min_high = 1;
1459  double min_low = 0;
1460 
1461  for (i=0; i<inner_loop_size; i++) {
1462  const double min_intensity = (min_high + min_low)/2;
1463 
1464  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1465  min_intensity, max_intensity,
1466  0, 1, 1, /* relaxation free */
1467  0, /* unused */
1469  starting_state);
1470 
1471  if (status != SUCCESS || ksepg_max_angle(flip_angles, num_echoes) > max_flip) {
1472  min_high = min_intensity;
1473  continue;
1474  }
1475 
1476  min_low = min_intensity;
1477 
1478  /* Calculate the objective by */
1479  KSEPG_STATE state = ksepg_duplicate_state(&starting_state);
1480  status = ksepg_get_intensities(flip_angles, num_echoes,
1481  state,
1482  relax_intensities,
1483  echo_spacing, T1, T2);
1484  ksepg_destruct_state(&state);
1485  KS_RAISE(status);
1486 
1487  int echo, center_echo;
1488  for (echo=0; echo < num_echoes; ++echo) {
1489  double r = relax_intensities[echo] / target_intensities[echo];
1490  double eff_TE = -T2 * log(r);
1491  if (eff_TE > target_eff_TE) {
1492  center_echo = echo > 1 ? echo -1 : 0;
1493  break;
1494  }
1495  }
1496 
1497  const double relative_distance = (center_echo - linear_sweep_center_echo)/normalizing_factor;
1498  const double objective = (relax_intensities[0] + 1) *
1499  (pow(relax_intensities[num_echoes-1], min_intensity_weight) + 1) /
1500  (pow(relative_distance, 2) + 1);
1501  if (opt_objective >= objective) {
1502  continue;
1503  }
1504 
1505  opt_objective = objective;
1506  opt_center_echo = center_echo;
1507  opt_max_intensity = max_intensity;
1508  opt_min_intensity = min_intensity;
1509  }
1510  }
1511 
1512  status = ksepg_track_bounded_curve(flip_angles, target_intensities, num_echoes,
1513  opt_min_intensity, opt_max_intensity,
1514  0, 1, 1, /* relaxation free */
1515  0, /* unused */
1517  starting_state);
1518  KS_RAISE(status);
1519 
1520  if (_center_echo) { *_center_echo = opt_center_echo; };
1521 
1522  return SUCCESS;
1523 
1524 } /* ksepg_optimize_linear_free_center_echo() */
STATUS ksepg_get_intensities(const double *flip_angles, int num_echoes, KSEPG_STATE state, double *signal_intensities, double echo_spacing, double T1, double T2)
ADDTITLEHERE
Definition: ksepg.cc:186
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
double ksepg_max_angle(double *flip_angles, int num_echoes)
Returns the maximum refocusing angle
Definition: ksepg.cc:631
KSEPG_STATE ksepg_duplicate_state(const KSEPG_STATE *state)
Duplicate an EPG&#39;s state
Definition: ksepg.cc:66
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
STATUS ksepg_track_bounded_curve(double *flip_angles, double *target_intensities, int num_echoes, double min_intensity, double max_intensity, double echo_spacing, double T1, double T2, double center_position, STATUS(*generate_bounded_curve)(double *, int, double, double, double), const KSEPG_STATE starting_state)
Definition: ksepg.cc:860
STATUS ksepg_generate_intensity_linear(double *target_intensities, int num_echoes, double center_position, double min_intensity, double max_intensity)
ADDTITLEHERE
Definition: ksepg.cc:843
#define KS_THROW(format,...)
Definition: KSFoundation.h:181

◆ ksepg_optimize_linear_free_center_echo_std()

STATUS ksepg_optimize_linear_free_center_echo_std ( int *  center_echo,
int  target_eff_TE,
int  linear_sweep_center_echo,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
center_echoADDTEXTHERE
[in]target_eff_TEADDTEXTHERE
[in]linear_sweep_center_echoADDTEXTHERE
[in]flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1533  {
1534  const int state_size = 2*num_echoes + 1;
1535  KSEPG_STATE state = ksepg_create_state(state_size);
1536  state.data[0] = 1;
1537  state.data[1] = 1;
1538 
1539  STATUS s = ksepg_optimize_linear_free_center_echo(center_echo,
1540  target_eff_TE, linear_sweep_center_echo,
1541  flip_angles, num_echoes,
1542  max_flip, min_intensity_weight,
1543  echo_spacing, T1, T2,
1544  state);
1545  ksepg_destruct_state(&state);
1546 
1547  KS_RAISE(s);
1548 
1549  return SUCCESS;
1550 
1551 } /* ksepg_optimize_linear_free_center_echo_std() */
double * data
Definition: ksepg.h:43
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS ksepg_optimize_linear_free_center_echo(int *_center_echo, int target_eff_TE, int linear_sweep_center_echo, double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
Joint VFA modulation and center echo selection from TE
Definition: ksepg.cc:1419
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_optimize_linear_free_center_echo_long()

STATUS ksepg_optimize_linear_free_center_echo_long ( int *  center_echo,
int  target_eff_TE,
int  linear_sweep_center_echo,
double *  flip_angles,
int  num_echoes,
double  max_flip,
double  min_intensity_weight,
double  echo_spacing,
double  T1,
double  T2 
)

ADDTITLEHERE

ADDDESCHERE

Parameters
center_echoADDTEXTHERE
[in]target_eff_TEADDTEXTHERE
[in]linear_sweep_center_echoADDTEXTHERE
flip_anglesADDTEXTHERE
[in]num_echoesADDTEXTHERE
[in]max_flipADDTEXTHERE
[in]min_intensity_weightADDTEXTHERE
[in]echo_spacingADDTEXTHERE
[in]T1ADDTEXTHERE
[in]T2ADDTEXTHERE
Return values
STATUSSUCCESS or FAILURE
1560  {
1561  const int state_size = 2*num_echoes + 3;
1562 
1563  KS_MAT3x3 rot;
1564  KSEPG_RELAXATION rel = ksepg_create_relaxation(echo_spacing/2, T1, T2);
1565 
1566  KSEPG_STATE state = ksepg_create_state(state_size);
1567  state.data[0] = 1;
1568  state.data[1] = 1;
1569 
1570  /* apply a first refocusing of 90 degrees */
1571  ksepg_compute_rotation(&rot, PI/2);
1572  ksepg_next_echo(&state, &rot, rel);
1573 
1574  STATUS s = ksepg_optimize_linear_free_center_echo(center_echo,
1575  target_eff_TE, linear_sweep_center_echo,
1576  flip_angles, num_echoes,
1577  max_flip, min_intensity_weight,
1578  echo_spacing, T1, T2,
1579  state);
1580  ksepg_destruct_state(&state);
1581 
1582  KS_RAISE(s);
1583 
1584  return SUCCESS;
1585 
1586 } /* ksepg_optimize_linear_free_center_echo_long() */
double * data
Definition: ksepg.h:43
KSEPG_RELAXATION ksepg_create_relaxation(double time_delta, double T1, double T2)
Create a relaxation operator
Definition: ksepg.cc:31
Relaxation operator
Definition: ksepg.h:54
void ksepg_compute_rotation(KS_MAT3x3 *rot, double flip)
Compute the rotation matrix corresponding to a refocusing pulse
Definition: ksepg.cc:113
double KS_MAT3x3[9]
Definition: KSFoundation.h:354
void ksepg_next_echo(KSEPG_STATE *state, KS_MAT3x3 *rot, KSEPG_RELAXATION rel_op)
Advance the EPG state from an echo to the next
Definition: ksepg.cc:175
Extended phase graph state
Definition: ksepg.h:41
#define KS_RAISE(status)
Definition: KSFoundation.h:190
STATUS ksepg_optimize_linear_free_center_echo(int *_center_echo, int target_eff_TE, int linear_sweep_center_echo, double *flip_angles, int num_echoes, double max_flip, double min_intensity_weight, double echo_spacing, double T1, double T2, const KSEPG_STATE starting_state)
Joint VFA modulation and center echo selection from TE
Definition: ksepg.cc:1419
void ksepg_destruct_state(KSEPG_STATE *state)
Free an EPG state&#39;s memory
Definition: ksepg.cc:57
KSEPG_STATE ksepg_create_state(int size)
Create a new EPG state with a certain maximum number of dephasing steps
Definition: ksepg.cc:44

◆ ksepg_sineTRAPS()

STATUS ksepg_sineTRAPS ( double *  flip_angles,
int  etl,
int  n23,
int  n4,
double  an1,
double  an23,
double  an4 
)

Generates an array of refocusing flip angles in the shape of a sinusoidal TRAPS scheme

Legacy function, please use ksepg_sineTRAPS2 instead.

From the following paper: Weigel, M., & Hennig, J. (2006). Contrast behavior and relaxation effects of conventional and hyperecho-turbo spin echo sequences at 1.5 and 3 T. Magnetic Resonance in Medicine: Official Journal of the Society of Magnetic Resonance in Medicine / Society of Magnetic Resonance in Medicine, 55(4), 826–835.

Parameters
[out]flip_anglesArray of flip angles [degrees]
[in]etlNumber of refocusing pulses
[in]n23Index at the FA peak
[in]n4Index at the start of the tail
[in]an1RF amplitude at the start of the first ramp [degrees]
[in]an23RF amplitude on the plateau [degrees]
[in]an4RF amplitude on the tail [degrees]
Return values
STATUSSUCCESS or FAILURE
1601  {
1602 
1603 
1604  double scale_fact = 0.92;
1605  int n1 = 2;
1606  int index = 0;
1607  int i;
1608 
1609  /* Calculate length of stuff */
1610  int tail = etl - 2;
1611  int n_sine_a = n23 - n1;
1612  int n_flat = etl - n4;
1613  int n_sine_d = tail - n_sine_a + 1 - n_flat;
1614 
1615  /* TODO: error checking */
1616 
1617  /* Ramp */
1618  double a1 = 0.6;
1619  double a2 = 0.1;
1620 
1621  flip_angles[index++] = an1+a1*(180.0-an1);
1622  flip_angles[index++] = an1+a2*(180.0-an1);
1623 
1624  /* Acending sine */
1625  an23 /= scale_fact;
1626  for (i = 0; i < n_sine_a; i++) {
1627 
1628  double radi = (-PI/2.0) + ((PI/2.0)/(n_sine_a-1))*i;
1629 
1630  double flip_ratio = 1.0 + (((an23/an1/2.0)-1)/(n_sine_a-1))*i;
1631  flip_ratio *= an1;
1632 
1633  flip_angles[index++] = (sin(radi)+2) * flip_ratio;
1634 
1635  }
1636  flip_angles[index-1] *= scale_fact;
1637 
1638  /* Decending sine */
1639  for (i = 0; i < n_sine_d; i++) {
1640 
1641  double radi = -PI + ((PI/2.0)/(n_sine_d-1))*i;
1642 
1643  double start = (an23/an4/2);
1644  double flip_ratio = start + ((1-start)/(n_sine_d-1))*i;
1645  flip_ratio *= an4;
1646 
1647  if (i != 0) {
1648  flip_angles[index++] = (sin(radi)+2) * flip_ratio;
1649  }
1650 
1651  }
1652 
1653  /* Flat */
1654  for (i = 0; i < n_flat; i++) {
1655  flip_angles[index++] = an4;
1656  }
1657 
1658  return SUCCESS;
1659 
1660 } /* ksepg_sineTRAPS() */

◆ ksepg_sineTRAPS2()

STATUS ksepg_sineTRAPS2 ( float *  flip_angles,
int  etl,
KSEPG_TRAPS_DESIGN  traps_design,
float  scaling_factor 
)

Generates an array of refocusing flip angles in the shape of a sinusoidal TRAPS scheme

From the following paper: Weigel, M., & Hennig, J. (2006). Contrast behavior and relaxation effects of conventional and hyperecho-turbo spin echo sequences at 1.5 and 3 T. Magnetic Resonance in Medicine: Official Journal of the Society of Magnetic Resonance in Medicine / Society of Magnetic Resonance in Medicine, 55(4), 826–835.

Parameters
[out]flip_anglesArray of flip angles [degrees]
[in]etlNumber of refocusing pulses
[in]traps_designDesign structure
[in]scaling_factorScaling factor for all flip angles (1.0 recommended)
Return values
STATUSSUCCESS or FAILURE
1668  {
1669 
1670  /* rule of thumb the lower an1 the longer the ramp needed to get into pseudo steady state (PSS) */
1671  float ramp[3];
1672  switch(traps_design.ramp_length) {
1673  case 1:
1674  ramp[0] = 0.45;
1675  break;
1676  case 2:
1677  ramp[0] = 0.6;
1678  ramp[1] = 0.1;
1679  break;
1680  case 3:
1681  ramp[0] = 0.6;
1682  ramp[1] = 0.1;
1683  ramp[2] = 0.05;
1684  break;
1685  default:
1686  return KS_THROW("ramp_length must be 1,2 or 3");
1687  }
1688 
1689  if (traps_design.n1 < traps_design.ramp_length || traps_design.n1 >= traps_design.n2 /*space for n23 and n4*/){
1690  return KS_THROW("n1 must fullfill ramp_length <= n1 < n2 (ramp_length=%d, n1=%d, n2=%d)",
1691  traps_design.ramp_length, traps_design.n1, traps_design.n2);
1692  }
1693 
1694  /*n2 and n3 can be identical*/
1695  if (traps_design.n2 > traps_design.n3){
1696  return KS_THROW("n2 must be <= n3 (n2=%d, n3=%d)", traps_design.n2, traps_design.n3);
1697  }
1698 
1699  if (traps_design.n3 >= traps_design.n4){
1700  return KS_THROW("n3 must be < n4 (n3=%d, n4=%d)", traps_design.n3, traps_design.n4);
1701  }
1702 
1703  if (traps_design.n4 > etl){
1704  return KS_THROW("n4 must be <= etl (n4=%d, etl=%d)", traps_design.n4, etl);
1705  }
1706 
1707  if (scaling_factor < 0 || scaling_factor > 1){
1708  return KS_THROW("scaling factor %f out of bound [0 1]", scaling_factor);
1709  }
1710 
1711  int i;
1712  for (i=0; i<traps_design.ramp_length; i++){
1713  flip_angles[i] = (traps_design.an1+ramp[i]*(180.0-traps_design.an1))*scaling_factor;
1714  }
1715 
1716  for (i=traps_design.ramp_length; i<traps_design.an1; i++){
1717  flip_angles[i] = traps_design.an1*scaling_factor;
1718  }
1719 
1720  /*acending sine from an1 to an23*/
1721  double radi;
1722  int n_sine_a = traps_design.n2 - traps_design.n1;
1723  if (n_sine_a == 1){
1724  n_sine_a = 0; /* avoid devision by 0 in the loop below, in this case the value of n_sine_a is irrelevant as (i-n1) will be zero */
1725  }
1726 
1727  for (i=traps_design.n1; i<traps_design.n2; i++){
1728  radi = (-PI/2.0) + ((PI)/(n_sine_a-1))*(i-traps_design.n1);
1729  flip_angles[i] = ((sin(radi)+1)/2 * (traps_design.an23-traps_design.an1) + traps_design.an1)*scaling_factor;
1730  }
1731 
1732  /* Plateau, if n2 == n3 --> no plateau */
1733  for (i=traps_design.n2; i<traps_design.n3; i++){
1734  flip_angles[i] = traps_design.an23;
1735  }
1736 
1737  /*decending sine*/
1738  int n_sine_d = traps_design.n4 - traps_design.n3;
1739  if (n_sine_d == 1){
1740  n_sine_d = 0; /* avoid devision by 0 in the loop below, in this case the value of n_sine_a is irrelevant as (n3 - i) will be zero */
1741  }
1742  for (i=traps_design.n3; i<traps_design.n4; i++){
1743  radi = (PI/2.0) + ((PI)/(n_sine_d-1))*(traps_design.n3-i);
1744  flip_angles[i] = ((sin(radi)+1)/2 * (traps_design.an23-traps_design.an4) + traps_design.an4)*scaling_factor;
1745  }
1746 
1747  /* tail */
1748  for (i=traps_design.n4; i<etl; i++){
1749  flip_angles[i] = traps_design.an4*scaling_factor;
1750  }
1751 
1752  /*KS_THROW("etl=%d, ramp_length=%d, n1=%d, n2=%d, n3=%d, n4=%d, an1=%0.1f, an23=%0.1f, an4=%0.1f", etl, ramp_length, n1, n2, n3, n4, an1, an23, an4);*/
1753  /*
1754  for (i=0; i<etl; i++){
1755  KS_THROW("flip(%d)=%0.2f",i,flip_angles[i]);
1756  }
1757  */
1758 
1759  return SUCCESS;
1760 
1761 } /* ksepg_sineTRAPS2() */
int n2
Definition: ksepg.h:842
int n3
Definition: ksepg.h:843
float an1
Definition: ksepg.h:845
float an23
Definition: ksepg.h:846
int n4
Definition: ksepg.h:844
float an4
Definition: ksepg.h:847
int ramp_length
Definition: ksepg.h:840
#define KS_THROW(format,...)
Definition: KSFoundation.h:181
int n1
Definition: ksepg.h:841

◆ ksepg_calc_relSAR()

double ksepg_calc_relSAR ( double *  flip_angles,
int  etl 
)

Computes the SAR value relative to a train with just 180° refocusing pulses

Parameters
[in]flip_anglesRefocusing flip angles
[in]etlNumber of echoes in the train
Returns
double Relative SAR
1766  {
1767 
1768  int i;
1769  double sumOfFAs = 0.0;
1770 
1771  for (i = 0; i < etl; i++) {
1772  sumOfFAs += pow(flip_angles[i]/180,2);
1773  }
1774 
1775  return (1.0/(0.25+etl)) * (0.25 + sumOfFAs);
1776 
1777 } /* ksepg_calc_relSAR() */

Variable Documentation

◆ rhkacq_uid

int rhkacq_uid

◆ ks_plot_filefmt

int ks_plot_filefmt

◆ ks_plot_kstmp

int ks_plot_kstmp

◆ ks_psdname

char ks_psdname[256]