void calc_readout(READOUT_GRADIENT_T *grad, int write_flag, char VJparam_g[], char VJparam_sw[], char VJparam_at[]) { if ((ix > 1) && !sglarray) return; if ((grad->enableButterfly) && (grad->cr1amp > grad->maxGrad)) { sgl_abort_message("ERROR gradient %s: Crusher amplitude (%.2f) exceeds maximum (%.2f)", grad->name,grad->cr1amp,grad->maxGrad); } grad->writeToDisk = write_flag; /* assign writeToDisk flag */ calcReadout(grad); /* calculate and create readout gradient */ if (grad->error == ERR_AMPLITUDE) { sgl_abort_message("ERROR gradient %s: FOV (RO) too small, increase to %.2fmm\n", /* grad->name,grad->acqTime * grad->gamma * grad->maxGrad * MM_TO_CM); */ grad->name,grad->bandwidth/(grad->gamma * grad->maxGrad * MM_TO_CM)); } /* return acquisition parameters to VnmrJ space */ if (strcmp(VJparam_g, "")) putvalue(VJparam_g, grad->roamp); if (strcmp(VJparam_sw, "")) putvalue(VJparam_sw, grad->bandwidth); if (strcmp(VJparam_at, "")) putvalue(VJparam_at, grad->acqTime); }
void calc_epi(EPI_GRADIENT_T *epi_grad, READOUT_GRADIENT_T *ro_grad, PHASE_ENCODE_GRADIENT_T *pe_grad, REFOCUS_GRADIENT_T *ror_grad, PHASE_ENCODE_GRADIENT_T *per_grad, READOUT_GRADIENT_T *nav_grad, int write_flag) { /* Variables for generating gradient shapes */ double dwint,blipint,skip,dw; int np_ramp, np_flat, npro; double *dwell, *dac; double pos, neg; int pt, pts, inx=0, lobe, lobes, blippts, zeropts; /* Variables for generating tables */ int n, seg, steps; char order_str[MAXSTR],gpe_tab[MAXSTR],tab_file[MAXSTR]; FILE *fp; /********************************************************************************/ /* Error Checks */ /********************************************************************************/ /* make sure that the combination of nseg, ky_order and fract_ky make sense */ if (ky_order[0] == 'c') { /* Can't do just one segment with centric */ if (nseg == 1) { if (ix == 1) { warn_message("WARNING %s: ky_order set to 'l'\n",seqfil); warn_message(" Only linear ordering allowed with single-shot acquisition\n"); } ky_order[0] = 'l'; } /* Must have even number of shots with centric ordering */ if (((int) nseg % 2) == 1) abort_message("ERROR %s: Must do even number of shots with centric ordering\n",seqfil); /* Can't do fractional ky with centric acquisition */ if (fract_ky != pe_grad->steps/2) abort_message("ERROR %s: fract_ky must be = nv/2 (%d) for centric acquisition\n",seqfil,(int) (pe_grad->steps/2)); } if (fract_ky > pe_grad->steps/2) abort_message("ERROR %s: fract_ky must be <= nv/2 (%d)\n",seqfil,(int) (pe_grad->steps/2)); /* calculate etl */ switch(ky_order[0]) { case 'l': epi_grad->etl = (pe_grad->steps/2 + fract_ky)/nseg; epi_grad->center_echo = fract_ky/nseg - 1; if (epi_grad->etl - ((int) epi_grad->etl) > 0.005) abort_message("%s: Echo train length ((%d/2+%d)/%d = %.2f) not an integer\n", seqfil,(int)pe_grad->steps,(int) fract_ky, (int) nseg,epi_grad->etl); break; case 'c': epi_grad->etl = pe_grad->steps/nseg; epi_grad->center_echo = 0; if (epi_grad->etl - ((int) epi_grad->etl) > 0.005) abort_message("%s: Echo train length (%d/%d) not an integer\n", seqfil,(int)pe_grad->steps,(int) nseg); break; default: abort_message("%s: ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n", seqfil, ky_order); break; } epi_grad->center_echo += ssepi*2; /********************************************************************************/ /* Generate a single phase encoding blip and the dephaser */ /********************************************************************************/ blipint = 1/(pe_grad->fov/10*nuc_gamma()); /* base step in PE dimension */ switch(ky_order[0]) { case 'l': /* each blip will jump nseg lines in ky: */ pe_grad->m0 = blipint*nseg; per_grad->steps = pe_grad->steps; /* each increment is = one blip unit */ per_grad->m0 = blipint*per_grad->steps/2; /* start at nv/2, step 1 */ break; case 'c': /* each blip will jump nseg/2 lines in ky: */ pe_grad->m0 = blipint*nseg/2; per_grad->steps = nseg; per_grad->m0 = blipint*per_grad->steps/2; /* start at nseg/2, step 1 */ break; default: abort_message("ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n",ky_order); break; } /* Phase encoding blip */ pe_grad->calcFlag = SHORTEST_DURATION_FROM_MOMENT; pe_grad->writeToDisk = FALSE; calcPhase(pe_grad); if ((pe_grad->duration < epi_grad->tblip) || (pe_grad->amp/pe_grad->tramp > pe_grad->slewRate)) { pe_grad->tramp = granularity(MAX(epi_grad->tblip/2,pe_grad->amp/pe_grad->slewRate),pe_grad->resolution); pe_grad->duration = 2*pe_grad->tramp; pe_grad->calcFlag = AMPLITUDE_FROM_MOMENT_DURATION_RAMP; calcPhase(pe_grad); } /* Phase encoding dephaser */ per_grad->calcFlag = SHORTEST_DURATION_FROM_MOMENT; per_grad->maxGrad *= glim; per_grad->writeToDisk = write_flag; calcPhase(per_grad); /* Now adjust the initial dephaser for fractional k-space */ per_grad->amp *= (fract_ky/(pe_grad->steps/2)); /* Create an array for dwell times */ npro = ro_grad->numPointsFreq; if ((dwell = (double *)malloc(sizeof(double)*npro)) == NULL) { abort_message("Can't allocate memory for dwell"); } /********************************************************************************/ /* Generate a single readout lobe */ /********************************************************************************/ ro_grad->writeToDisk = nav_grad->writeToDisk = FALSE; calcReadout(ro_grad); dw = granularity(1/sw,1/epi_grad->ddrsr); dwint = dw*ro_grad->amp; skip = getval("skip"); /* User specified min delay between acquisitions */ skip = MAX(skip,pe_grad->duration); /* Is PE blip longer? Then use that */ skip /= 2; /* in further calculations, skip is the skipped part on either ramp */ /* If RO ramp - skip isn't at least one dwell, then we can't do ramp sampling */ if (ro_grad->tramp - (skip + dw + getval("aqtm") - at) < dw) { if (rampsamp[0] == 'y') { printf("Blip duration or Min echo spacing is long (%.2fus), ramp sampling turned off",2*skip*1e6); rampsamp[0] = 'n'; } /* set ramp time and recalculate */ ro_grad->tramp = skip + (dw + getval("aqtm") - at); calcReadout(ro_grad); } /********************************************************************************/ if (rampsamp[0] == 'n') { /* No rampsampling, just use simple RO shape */ /********************************************************************************/ np_ramp = 0; np_flat = npro; skip = (ro_grad->atDelayFront + ro_grad->atDelayBack)/2; /* Set dwell array */ for (pt = 0; pt < npro; pt++) dwell[pt] = dw; dwell[npro-1] = 2*dw; /* gradient duration is actually dw too long */ } /********************************************************************************/ else { /* rampsampling */ /********************************************************************************/ calc_readout_rampsamp(ro_grad,dwell,&skip,&np_ramp); np_flat = npro - 2*np_ramp; } /* end if rampsampling = 'y' */ switch (ro_grad->error) { case ERR_NO_ERROR: break; case ERR_AMPLITUDE: abort_message("Readout gradient too large, increase FOV to %.2fmm", ro_grad->bandwidth/(ro_grad->gamma * ro_grad->maxGrad * MM_TO_CM)); break; default: abort_message("Error in calculation of readout gradient (error %d)", (int)ro_grad->error); break; } /* We now have a single lobe, keep that for the navigator echo */ nav_grad->amp = ro_grad->amp; nav_grad->duration = ro_grad->duration; nav_grad->tramp = ro_grad->tramp; nav_grad->m0 = ro_grad->m0; nav_grad->m0ref = ro_grad->m0ref; nav_grad->dataPoints = ro_grad->dataPoints; nav_grad->numPoints = ro_grad->numPoints; nav_grad->slewRate = ro_grad->slewRate; /********************************************************************************/ /* Readout dephaser */ /********************************************************************************/ ror_grad->balancingMoment0 = nav_grad->m0ref; /* ideal moment */ /* adjust with grora tweaker */ if (grora == 0) { warn_message("grora tweaker is 0, probably using old protocol - changed to 1.0"); grora = 1.0; } ror_grad->balancingMoment0 *= grora; ror_grad->writeToDisk = write_flag; calcRefocus(ror_grad); /********************************************************************************/ /* Expand gradient shapes to full echo train */ /********************************************************************************/ /* Readout - The navigator shape holds a single lobe */ /********************************************************************************/ /* Does positive or negative lobe need to be adjusted for tweaker? */ pos = neg = 1; if (groa >= 0) /* Adjust negative downwards, since positive is already at max */ neg = (1 - groa/nav_grad->amp); else /* groa < 0, Adjust positive downwards */ pos = (1 + groa/nav_grad->amp); /* Increase the size of ro shape to hold full shape */ /* free(ro_grad->dataPoints); Don't free this, it's now assigned to the navigator echo */ lobes = (epi_grad->etl + ssepi*2); ro_grad->numPoints *= lobes; if ((ro_grad->dataPoints = (double *)malloc(ro_grad->numPoints*sizeof(double))) == NULL) abort_message("%s: Problem allocating memory for EPI readout gradient",seqfil); ro_grad->duration *= lobes; /* Concatenate positive and negative lobes */ /* until we have a full echo train (plus ssepi) */ pts = nav_grad->numPoints; inx = 0; for (lobe = 0; lobe < lobes/2; lobe++) { for (pt = 0; pt < pts; pt++) ro_grad->dataPoints[inx++] = nav_grad->dataPoints[pt] * pos; for (pt = 0; pt < pts; pt++) ro_grad->dataPoints[inx++] = -nav_grad->dataPoints[pt] * neg; } /********************************************************************************/ /* Phase encoding */ /********************************************************************************/ /* Keep blip */ blippts = pe_grad->numPoints; if ((dac = (double *)malloc(blippts*sizeof(double))) == NULL) abort_message("%s: Problem allocating memory for EPI blip",seqfil); for (pt = 0; pt < blippts; pt++) dac[pt] = pe_grad->dataPoints[pt]; /* Increase the size of pe shape to hold full shape */ free(pe_grad->dataPoints); if ((pe_grad->dataPoints = (double *)malloc(ro_grad->numPoints*sizeof(double))) == NULL) abort_message("%s: Problem allocating memory for EPI phase encoding gradient",seqfil); /* Pad front of shape - including ssepi time - with zeros */ inx = 0; lobes = ssepi*2; zeropts = nav_grad->numPoints; for (lobe = 0; lobe < lobes; lobe++) { for (pt = 0; pt < zeropts; pt++) { pe_grad->dataPoints[inx++] = 0; } } zeropts = nav_grad->numPoints - blippts/2; for (pt = 0; pt < zeropts; pt++) pe_grad->dataPoints[inx++] = 0; lobes = epi_grad->etl-1; zeropts = nav_grad->numPoints - blippts; for (lobe=0; lobe < lobes; lobe++) { for (pt = 0; pt < blippts; pt++) pe_grad->dataPoints[inx++] = dac[pt]; for (pt = 0; pt < zeropts; pt++) pe_grad->dataPoints[inx++] = 0; } /* Add a few zeros, half the duration of the blip + one lobe, at the very end */ zeropts = blippts/2 + nav_grad->numPoints; zeropts = blippts/2; for (pt = 0; pt < zeropts; pt++) pe_grad->dataPoints[inx++] = 0; pe_grad->numPoints = ro_grad->numPoints; pe_grad->duration = ro_grad->duration; /********************************************************************************/ /* Keep some parameters in EPI struct */ /********************************************************************************/ epi_grad->skip = skip; epi_grad->np_flat = np_flat; epi_grad->np_ramp = np_ramp; epi_grad->dwell = dwell; epi_grad->duration = ro_grad->duration; epi_grad->numPoints = ro_grad->numPoints; epi_grad->amppos = nav_grad->amp*pos; epi_grad->ampneg = -nav_grad->amp*neg; epi_grad->amppe = pe_grad->amp; /********************************************************************************/ /* Write shapes to disk */ /********************************************************************************/ if (writeToDisk(ro_grad->dataPoints, ro_grad->numPoints, 0, ro_grad->resolution, TRUE /* rollout */, ro_grad->name) != ERR_NO_ERROR) abort_message("Problem writing shape %s (%d points) to disk", ro_grad->name,(int) ro_grad->numPoints); if (writeToDisk(nav_grad->dataPoints, nav_grad->numPoints, 0, nav_grad->resolution, TRUE /* rollout */, nav_grad->name) != ERR_NO_ERROR) abort_message("Problem writing shape %s (%d points) to disk", nav_grad->name,(int) nav_grad->numPoints); if (writeToDisk(pe_grad->dataPoints, pe_grad->numPoints, 0, pe_grad->resolution, TRUE /* rollout */, pe_grad->name) != ERR_NO_ERROR) abort_message("Problem writing shape %s (%d points) to disk", pe_grad->name,(int) pe_grad->numPoints); /********************************************************************************/ /* Create EPI tables */ /********************************************************************************/ /* Generates two tables: */ /* t1 that specifies the k-space ordering, used by recon_all */ /* t2 that specifies which direction in k-space to go in a given shot */ /* 1 = positive blips, and -1 = negative blips */ if ((epi_grad->table1 = (int *)malloc(pe_grad->steps*sizeof(int))) == NULL) abort_message("%s: Problem allocating memory for EPI table1",seqfil); if ((epi_grad->table2 = (int *)malloc(nseg*sizeof(int))) == NULL) abort_message("%s: Problem allocating memory for EPI table2",seqfil); switch(ky_order[0]) { case 'l': inx = 0; for (seg = 0; seg < nseg; seg++) { epi_grad->table1[inx++] = -fract_ky + seg; for (n = 0; n < epi_grad->etl-1; n++) { epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1]+nseg); inx++; } } for (seg = 0; seg < nseg; seg++) epi_grad->table2[seg] = 1; break; case 'c': inx = 0; for (seg = 0; seg < nseg; seg++) { epi_grad->table1[inx++] = -(nseg/2 - seg); for (n = 0; n < epi_grad->etl-1; n++) { if (epi_grad->table1[inx-1] >= 0) epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1] + nseg/2); else epi_grad->table1[inx] = (int) (epi_grad->table1[inx-1] - nseg/2); inx++; } } for (seg = 0; seg < nseg; seg++) epi_grad->table2[seg] = ((nseg/2 - 1 - seg >= 0) ? -1 : 1); break; default: /* This should have been caught earlier */ break; } steps = inx; /* Print table t1 to file in tablib */ switch(ky_order[0]) { case 'l': sprintf(order_str,"lin"); break; case 'c': sprintf(order_str,"cen"); break; default: abort_message("%s: ky_order %s not recognized, use 'l' (linear) or 'c' (centric)\n", seqfil,ky_order); } if (ky_order[1] == 'r') /* not reversed */ sprintf(gpe_tab,"%s_nv%d_f%d_%s%d_rev",seqfil, (int)pe_grad->steps,(int)fract_ky,order_str,(int)nseg); else sprintf(gpe_tab,"%s_nv%d_f%d_%s%d",seqfil, (int)pe_grad->steps,(int)fract_ky,order_str,(int)nseg); sprintf(tab_file,"%s/tablib/%s",userdir,gpe_tab); if ((fp = fopen(tab_file,"w")) == NULL) { abort_message("Error opening file %s\n",gpe_tab); } fprintf(fp,"t1 = "); for (inx = 0; inx < steps; inx++) { if (ky_order[1] == 'r') fprintf(fp,"%d ", epi_grad->table1[inx]); else fprintf(fp,"%d ", -epi_grad->table1[inx]); } fprintf(fp,"\n"); fclose(fp); strcpy(petable,gpe_tab); putstring("petable",gpe_tab); /* Return values in VnmrJ parameter pe_table */ putCmd("exists('pe_table','parameter'):$ex\n"); putCmd("if ($ex > 0) then\n"); putCmd(" pe_table = 0\n"); //reset pe_table array for (inx = 0; inx < steps; inx++) { putCmd(" pe_table[%d] = %d\n",inx+1, ((ky_order[1] == 'r') ? 1 : -1)*epi_grad->table1[inx]); } putCmd("endif\n"); }