pulsesequence() { /* Internal variable declarations *************************/ int shapelist90,shapelist180,shapelistIR; double nseg; double seqtime,tau1,tau2,tau3, te1_delay,te2_delay,te3_delay, iti_delay, ti_delay, tr_delay; double kzero; double freq90[MAXNSLICE], freq180[MAXNSLICE], freqIR[MAXNSLICE]; /* Real-time variables used in this sequence **************/ int vpe_ctr = v2; // PE loop counter int vpe_mult = v3; // PE multiplier, ranges from -PE/2 to PE/2 int vms_slices = v4; // Number of slices int vms_ctr = v5; // Slice loop counter int vseg = v6; // Number of ETL segments int vseg_ctr = v7; // Segment counter int vetl = v8; // Echo train length int vetl_ctr = v9; // Echo train loop counter int vssc = v10; // Compressed steady-states int vtrimage = v11; // Counts down from nt, trimage delay when 0 int vacquire = v12; // Argument for setacqvar, to skip steady state acquires int vphase180 = v13; // phase of 180 degree refocusing pulse /* Initialize paramaters **********************************/ init_mri(); /* Load external PE table ********************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); } else { abort_message("petable undefined"); } seqtime = 0.0; espmin = 0.0; kzero = getval("kzero"); /* RF Power & Bandwidth Calculations **********************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Initialize gradient structures *************************/ init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_slice(&ss_grad,"ss",thk); /* NOTE assume same band widths for p1 and p2 */ init_slice_butterfly(&ss2_grad,"ss2",thk,gcrush,tcrush); init_slice_refocus(&ssr_grad,"ssr"); /* Gradient calculations **********************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad,WRITE,"gpe","tpe"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p1_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); /* Equalize refocus and PE gradient durations *************/ calc_sim_gradient(&ror_grad,&null_grad,&ssr_grad,0.0,WRITE); /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') { init_rf(&ir_rf,pipat,pi,flipir,rof1,rof2); calc_rf(&ir_rf,"tpwri","tpwrif"); init_slice_butterfly(&ssi_grad,"ssi",thk,gcrushir,tcrushir); calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi"); } /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp, 0,freq90, ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); offsetlist(pss,ssi_grad.ssamp,0,freqIR, ns,seqcon[1]); shapelist90 = shapelist(p1pat,ss_grad.rfDuration, freq90, ns,0,seqcon[1]); shapelist180 = shapelist(p2pat,ss2_grad.rfDuration,freq180,ns,0,seqcon[1]); shapelistIR = shapelist(pipat,ssi_grad.rfDuration,freqIR, ns,0,seqcon[1]); /* same slice selection gradient and RF pattern used */ if (ss_grad.rfFraction != 0.5) abort_message("ERROR %s: RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss_grad.rfFraction); if (ro_grad.echoFraction != 1) abort_message("ERROR %s: Echo Fraction must be 1",seqfil); /* Find sum of all events in each half-echo period ********/ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + pe_grad.duration + ro_grad.timeToEcho; tau3 = ro_grad.timeFromEcho + pe_grad.duration + ss2_grad.rfCenterFront; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing if (minesp[0] == 'y') { esp = espmin + 8e-6; // ensure at least 4us delays in both TE periods putvalue("esp",esp); } else if (((espmin+8e-6)-esp) > 12.5e-9) { abort_message("ERROR %s: Echo spacing too small, minimum is %.2fms\n",seqfil,(espmin+8e-6)*1000); } te1_delay = esp/2.0 - tau1; // Intra-esp delays te2_delay = esp/2.0 - tau2; te3_delay = esp/2.0 - tau3; te = kzero*esp; // Return effective TE putvalue("te",te); /* Minimum TR **************************************/ /* seqtime is total time per slice */ seqtime = 2*4e-6 + ss_grad.rfCenterFront + etl*esp + ro_grad.timeFromEcho + pe_grad.duration + te3_delay; /* Increase TR if any options are selected****************/ if (sat[0] == 'y') seqtime += ns*satTime; if (fsat[0] == 'y') seqtime += ns*fsatTime; if (mt[0] == 'y') seqtime += ns*mtTime; if (ir[0] == 'y') { /* Inter-IR delay */ if (ns > 1) iti_delay = seqtime - ssi_grad.duration; /* it is probably safe to assume that seqtime is always > the pulse widths */ else iti_delay = 0; /* Inversion Recovery */ timin = ssi_grad.rfCenterBack + ss_grad.rfCenterFront; timin += 8e-6; // from sp1on/off and after 90 pulse power setting timin += seqtime*(ns-1) + iti_delay; if (ti < timin + 4e-6) // ensure at least a 4us delay abort_message("%s: ti too short, minimum is %.2fms",seqfil,timin*1000); /* Delay after the last IR pulse */ ti_delay = ti - timin; /* force all slices to be acquired back-to-back, with a single TR delay at end */ trtype = 1; } else { iti_delay = ti_delay = 0; } trmin = ns*(seqtime + 4e-6); if (ir[0] == 'y') { trmin += (4e-6 + ssi_grad.rfCenterFront + ti); } if (mintr[0] == 'y'){ tr = trmin; putvalue("tr",tr); } if ((trmin-tr) > 12.5e-9) { abort_message("TR too short. Minimum TR = %.2fms\n",trmin*1000); } tr_delay = (tr - trmin)/ns; /* Set number of segments for profile or full image **********/ nseg = prep_profile(profile[0],nv/etl,&pe_grad,&per_grad); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Calculate total acquisition time */ g_setExpTime(tr*(nt*nseg*getval("arraydim") + ssc) + trimage*getval("arraydim")); /* Return parameters to VnmrJ */ putvalue("rgss",ss_grad.tramp); //90 slice ramp if (ss2_grad.enableButterfly) { //180 slice ramps putvalue("rcrush",ss2_grad.crusher1RampToCrusherDuration); putvalue("rgss2",ss2_grad.crusher1RampToSsDuration); } else { putvalue("rgss2",ss2_grad.tramp); } if (ro_grad.enableButterfly) { putvalue("rgro",ro_grad.crusher1RampToSsDuration); } else { putvalue("rgro",ro_grad.tramp); //RO ramp } putvalue("tror",ror_grad.duration); //ROR duration putvalue("rgror",ror_grad.tramp); //ROR ramp putvalue("gpe",pe_grad.peamp); //PE max amp putvalue("gss",ss_grad.ssamp); putvalue("gro",ro_grad.roamp); /* PULSE SEQUENCE *************************************/ initval(fabs(ssc),vssc); // Compressed steady-state counter assign(one,vacquire); // real-time acquire flag /* Phase cycle: Alternate 180 phase to cancel residual FID */ mod2(ct,vphase180); // 0101 dbl(vphase180,vphase180); // 0202 add(vphase180,one,vphase180); // 1313 Phase difference from 90 add(vphase180,oph,vphase180); obsoffset(resto); delay(4e-6); initval(nseg,vseg); loop(vseg,vseg_ctr); /* TTL scope trigger **********************************/ sp1on(); delay(4e-6); sp1off(); /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vseg_ctr,vssc,vseg_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); ifzero(vseg_ctr); assign(zero,vacquire); // Start acquiring when vseg_ctr reaches zero endif(vseg_ctr); setacqvar(vacquire); // Turn on acquire when vacquire is zero if (ticks) { xgate(ticks); grad_advance(gpropdelay); delay(4e-6); } if(ir[0] == 'y') { /* IR for all slices prior to data acquisition */ obspower(ir_rf.powerCoarse); obspwrf(ir_rf.powerFine); delay(4e-6); msloop(seqcon[1],ns,vms_slices,vms_ctr); obl_shapedgradient(ssi_grad.name,ssi_grad.duration,0,0,ssi_grad.amp,NOWAIT); delay(ssi_grad.rfDelayFront); shapedpulselist(shapelistIR,ssi_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ssi_grad.rfDelayBack); delay(iti_delay); endmsloop(seqcon[1],vms_ctr); delay(ti_delay); } msloop(seqcon[1],ns,vms_slices,vms_ctr); /* Prepulse options ***********************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* 90 degree pulse ************************************/ rotate(); obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(4e-6); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shapelist90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Read dephase and Slice refocus *********************/ obl_shapedgradient(ssr_grad.name,ssr_grad.duration,ror_grad.amp,0.0,-ssr_grad.amp,WAIT); /* First half-TE delay ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(te1_delay); peloop(seqcon[2],etl,vetl,vetl_ctr); mult(vseg_ctr,vetl,vpe_ctr); add(vpe_ctr,vetl_ctr,vpe_ctr); getelem(t1,vpe_ctr,vpe_mult); /* 180 degree pulse *******************************/ /* Note, ss2_grad.amp is max gradient for butterfly shape; flat top = _.ssamp */ obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shapelist180,ss2_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); /* Phase-encode gradient ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,vpe_mult,WAIT); /* Second half-TE period ******************************/ delay(te2_delay); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront); /* Acquire data ****************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ********************/ /* Phase encode, refocus, and dephase gradient ******************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,vpe_mult,WAIT); /* Second half-TE delay *******************************/ delay(te3_delay); endpeloop(seqcon[2],vetl_ctr); /* Relaxation delay ***********************************/ if (!trtype) delay(tr_delay); endmsloop(seqcon[1],vms_ctr); if (trtype) delay(ns*tr_delay); endloop(vseg_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
pulsesequence() { /* Internal variable declarations *************************/ /*timing*/ double tr_delay; double te_d1,te_d2,te_d3; /* delays */ double tau1,tau2,tau3; /*voxel crusher multipliers */ double fx,fy,fz; /*localization parameters*/ double freq1,freq2,freq3; double vox1_cr,vox2_cr, vox3_cr; int nDim; double rprof,pprof,sprof; char profile_vox[MAXSTR],profile_ovs[MAXSTR]; double restol, resto_local, csd_ppm; /*phase cycle****/ int counter,noph; char autoph[MAXSTR], pcflag[MAXSTR]; int rf1_phase[64] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3}; int rf2_phase[64] = {0,0,0,0,2,2,2,2,1,1,1,1,3,3,3,3,0,0,0,0,2,2,2,2,1,1,1,1,3,3,3,3, 0,0,0,0,2,2,2,2,1,1,1,1,3,3,3,3,0,0,0,0,2,2,2,2,1,1,1,1,3,3,3,3}; int rf3_phase[64] = {0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3, 0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3,0,2,1,3}; /* Initialize paramaters **********************************/ init_mri(); //this gets all the parameters that are defined in acqparms.h, etc get_wsparameters(); get_ovsparameters(); rprof = getval("rprof"); pprof = getval("pprof"); sprof = getval("sprof"); //read the crusher factors that are designed to create grad on the same axis without refoc fx=getval("fx"); fy=getval("fy"); fz=getval("fz"); getstr("profile_vox",profile_vox); getstr("profile_ovs",profile_ovs); /*set voxel sizes for butterfly crushers to 10^6 to set the slice portion to zero ***/ vox1_cr=1000000; vox2_cr=1000000; vox3_cr=1000000; /***** RF power initialize *****/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof2); /***** Initialize gradient structs *****/ trampfixed=trise; //rise time =trise tcrush=granularity(tcrush,GRADIENT_RES); //this is to avoid the granularity errors //if trampfixed is used, rise time needs to be checked if (trise*2>tcrush){ abort_message("tcrush too short. Minimum tcrush = %fms \n",1000*trise*2); } if (gcrush>gmax){ abort_message("gcrush too large. Max gcrush = %f \n",gmax*0.95); } init_slice_butterfly(&vox1_grad,"vox1",vox1,gcrush,tcrush); init_slice_butterfly(&vox2_grad,"vox2",vox2,gcrush,tcrush); init_slice_butterfly(&vox3_grad,"vox3",vox3,gcrush,tcrush); init_slice_butterfly(&vox1_crush,"vox1_crush",vox1_cr,gcrush,tcrush); init_slice_butterfly(&vox2_crush,"vox2_crush",vox2_cr,gcrush,tcrush); init_slice_butterfly(&vox3_crush,"vox3_crush",vox3_cr,gcrush,tcrush); if (profile_vox[0] == 'y') { init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); } /***** RF and Gradient calculations *****/ calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); calc_slice(&vox1_grad,&p2_rf,WRITE,"gvox1"); calc_slice(&vox2_grad,&p2_rf,WRITE,"gvox2"); calc_slice(&vox3_grad,&p2_rf,WRITE,"gvox3"); calc_slice(&vox1_crush,&p2_rf,WRITE,"vox1_crush"); calc_slice(&vox2_crush,&p2_rf,WRITE,"vox2_crush"); calc_slice(&vox3_crush,&p2_rf,WRITE,"vox3_crush"); if (profile_vox[0] == 'y') { calc_readout(&ro_grad,WRITE,"gro","sw","at"); putvalue("gro",ro_grad.roamp); // RO grad calc_readout_refocus(&ror_grad,&ro_grad,WRITE,"gror"); putvalue("tror",ror_grad.duration); // ROR duration } //set all gradients along a particular direction to zero if profile is needed if (profile_ovs[0]=='y'){ if (rprof==1) { vox1_grad.amp=0; //set slice selection in read direction to none vox3_crush.amp=0; // set corresponding crusher gradients to none } else if(pprof==1) { vox2_grad.amp=0; vox1_crush.amp=0; } else if(sprof==1) { vox3_grad.amp=0; vox2_crush.amp=0; } } /* Optional OVS and Water Suppression */ if (ovs[0] == 'y') create_ovsbands(); if (sat[0] == 'y') create_satbands(); if (ws[0] == 'y') create_watersuppress(); //Read in parameters not defined in acqparms.h and sglHelper nDim=getval("nDim"); restol=getval("restol"); //local frequency offset roff=getval("roff"); //receiver offset csd_ppm=getval("csd_ppm"); //chemical shift displacement factor noph=getval("noph"); getstr("autoph",autoph); getstr("pcflag",pcflag); settable(t3,noph,rf1_phase); settable(t2,noph,rf2_phase); settable(t1,noph,rf3_phase); /* tau1, tau2 and tau3 are sums of all events in TE*/ tau1 = vox1_grad.rfCenterFront+GDELAY+rof2; tau2 = vox1_grad.rfCenterBack + vox1_grad.rfCenterFront+2*(GDELAY+rof2); tau3 = vox3_grad.rfCenterBack+GDELAY+rof2; temin = tau1+5.0*tau2+tau3; if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (te < temin) { abort_message("te too short. Minimum te = %.2f ms\n",temin*1000); } /***** Calculate TE delays *****/ te_d1 = te/12.0 - tau1+GDELAY; te_d2 = te/6.0 - tau2+2*(GDELAY+rof2); te_d3 = te/12.0 - tau3+GDELAY+rof2; //Calculate delta from resto to include local frequency line+ chemical shift offset resto_local=resto-restol; /***** Min TR *****/ trmin = GDELAY + p1 + te + at+rof1+rof2; if (ws[0] == 'y') trmin += wsTime; if (ovs[0] == 'y') trmin += ovsTime; if (sat[0] == 'y') trmin += satTime; if (profile_vox[0] == 'y') trmin += ror_grad.duration + ro_grad.duration - at; if (mintr[0] == 'y') { tr = trmin; // ensure at least 4us between gradient events putvalue("tr",tr); } if ((trmin-tr) > 12.5e-9) { abort_message("TR too short. Minimum TR= %.2fms\n",trmin*1000); } /***** Calculate TR delay *****/ tr_delay = tr - trmin; /* Frequency offsets */ freq1 = poffset(pos1,vox1_grad.ssamp); // First RF pulse freq2 = poffset(pos2,vox2_grad.ssamp); // Second RF pulse freq3 = poffset(pos3,vox3_grad.ssamp); // Third RF pulse freq1=freq1-csd_ppm*sfrq; freq2=freq2-csd_ppm*sfrq; freq3=freq3-csd_ppm*sfrq; /* Frequency offsets */ if (profile_vox[0] == 'y') { /* Shift DDR for pro ************************************/ roff = -poffset(pro,ro_grad.roamp); } /* Put gradient information back into VnmrJ parameters */ putvalue("gvox1",vox1_grad.ssamp); putvalue("gvox2",vox2_grad.ssamp); putvalue("gvox3",vox3_grad.ssamp); putvalue("rgvox1",vox1_grad.tramp); putvalue("rgvox2",vox2_grad.tramp); putvalue("rgvox3",vox3_grad.tramp); sgl_error_check(sglerror); if (ss<0) g_setExpTime(tr*(nt-ss)*arraydim); else g_setExpTime(tr*(nt*arraydim+ss)); /**[2.7] PHASE CYCLING ******************************************************/ assign(zero, oph); counter=(double)nt*(ix-1); if (autoph[0] == 'n') counter=0.0; //only goes through nt, if 'y' goes through nt*array initval(counter,v1); initval(noph,v3); add(v1,ct,v2); modn(v2,v3,v2); /* Full phase cycling requires 64 steps*/ if (pcflag[0] == 'n') { assign(zero,v2); getelem(t1,v2,v10); getelem(t2,v2,v11); getelem(t3,v2,v12); } else { getelem(t1,v2,v10); getelem(t2,v2,v11); getelem(t3,v2,v12); } /*Start of the sequence*/ obsoffset(resto_local); // need it here for water suppression to work delay(GDELAY); rot_angle(vpsi,vphi,vtheta); if (ticks) { xgate(ticks); grad_advance(gpropdelay); delay(4e-6); } /* TTL scope trigger **********************************/ //sp1on(); delay(4e-6); sp1off(); /* Saturation bands ***********************************/ if (ovs[0] == 'y') ovsbands(); if (sat[0] == 'y') satbands(); /* Water suppression **********************************/ if (ws[0] == 'y') watersuppress(); /* Slice selective 90 degree RF pulse *****/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GDELAY); shaped_pulse(p1pat,p1,zero,rof1,rof2); /* start localization */ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); if (nDim > 2.5) { delay(te_d1); //this is at least GDELAY == 4 us obl_shaped3gradient(vox1_grad.name,vox1_crush.name,"",vox1_grad.duration,vox1_grad.amp,fy*vox1_crush.amp,0,NOWAIT); delay(vox1_grad.rfDelayFront); if (profile_ovs[0]=='y'&& rprof==1) freq1=0.0; shapedpulseoffset(p2_rf.pulseName,vox1_grad.rfDuration,v12,rof1,rof2,freq1); delay(vox1_grad.rfDelayBack); delay(te_d2); obl_shaped3gradient (vox1_grad.name,vox1_crush.name,"",vox1_grad.duration,vox1_grad.amp,fy*0.777*vox1_crush.amp,0,NOWAIT); delay(vox1_grad.rfDelayFront); if (profile_ovs[0]=='y'&& rprof==1) freq1=0.0; shapedpulseoffset(p2_rf.pulseName,vox1_grad.rfDuration,v12,rof1,rof2,freq1); delay(vox1_grad.rfDelayBack); delay(te_d2); } if (nDim > 1.5) { //this is 2nd slice selection obl_shaped3gradient("",vox2_grad.name,vox2_crush.name,vox2_grad.duration,0,vox2_grad.amp,fz*vox2_crush.amp,NOWAIT); delay(vox2_grad.rfDelayFront); if (profile_ovs[0]=='y'&& pprof==1) freq2=0.0; shapedpulseoffset(p2_rf.pulseName,vox2_grad.rfDuration,v11,rof1,rof2,freq2); delay(vox2_grad.rfDelayBack); delay(te_d2); obl_shaped3gradient("",vox2_grad.name,vox2_crush.name,vox2_grad.duration,0,vox2_grad.amp,fz*0.777*vox2_crush.amp,NOWAIT); delay(vox2_grad.rfDelayFront); if (profile_ovs[0]=='y'&& pprof==1) freq2=0.0; shapedpulseoffset(p2_rf.pulseName,vox2_grad.rfDuration,v11,rof1,rof2,freq2); delay(vox2_grad.rfDelayBack); delay(te_d2); } if (nDim > 0.5){ //this is 3rd slice selection obl_shaped3gradient(vox3_crush.name,"",vox3_grad.name,vox3_grad.duration,fx*vox3_crush.amp,0,vox3_grad.amp,NOWAIT); delay(vox3_grad.rfDelayFront); if (profile_ovs[0]=='y'&& sprof==1) freq3=0.0; shapedpulseoffset(p2_rf.pulseName,vox3_grad.rfDuration,v10,rof1,rof2,freq3); delay(vox3_grad.rfDelayBack); delay(te_d2); obl_shaped3gradient(vox3_crush.name,"",vox3_grad.name,vox3_grad.duration,fx*vox3_crush.amp,0,vox3_grad.amp,NOWAIT); delay(vox3_grad.rfDelayFront); if (profile_ovs[0]=='y'&& sprof==1) freq3=0.0; shapedpulseoffset(p2_rf.pulseName,vox3_grad.rfDuration,v10,rof1,rof2,freq3); delay(vox3_grad.rfDelayBack); delay(te_d3); } if (profile_vox[0] == 'y') { obl_shapedgradient(ror_grad.name,ror_grad.duration, -rprof*ror_grad.amp,-pprof*ror_grad.amp,-sprof*ror_grad.amp,WAIT); delay(GDELAY); obl_shapedgradient(ro_grad.name,ro_grad.duration, rprof*ro_grad.amp,pprof*ro_grad.amp,sprof*ro_grad.amp,NOWAIT); delay(ro_grad.atDelayFront); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); } else { startacq(alfa); acquire(np,1.0/sw); endacq(); } delay(tr_delay);
pulsesequence() { /* Internal variable declarations *********************/ double freq90[MAXNSLICE],freq180[MAXNSLICE]; double te_delay1,te_delay2,tr_delay,tau1,tau2,thk2fact,te_delay3=0.0,te_delay4=0.0,navTime=0.0; double crushm0,pem0,gcrushr,gcrushp,gcrushs,pecrush; double refsign=1,crushsign=1,navsign=1; int shape90,shape180,table=0,sepRefocus; char slprofile[MAXSTR]; /* sequence dependent diffusion variables */ double Gro,Gss; // "gdiff" for readout/readout refocus and slice/slice refocus double dgro,dgss; // "delta" for readout/readout refocus and slice/slice refocus double Dgro,Dgss; // "DELTA" for readout/readout refocus and slice/slice refocus double dcrush,dgss2; // "delta" for crusher and gss2 gradients double Dcrush,Dgss2; // "DELTA" for crusher and gss2 gradients int i; /* Real-time variables used in this sequence **********/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vms_slices = v3; // Number of slices int vms_ctr = v4; // Slice loop counter int vpe_offset = v5; // PE/2 for non-table offset int vpe_mult = v6; // PE multiplier, ranges from -PE/2 to PE/2 int vph180 = v7; // Phase of 180 pulse int vph2 = v8; // alternate phase of 180 on odd transients int vssc = v9; // Compressed steady-states int vtrimage = v10; // Counts down from nt, trimage delay when 0 int vacquire = v11; // Argument for setacqvar, to skip steady state acquires int vtrigblock = v12; // Number of slices per trigger block /* Initialize paramaters *****************************/ init_mri(); thk2fact=getval("thk2fact"); pecrush=getval("pecrush"); sepRefocus=getvalnwarn("sepRefocus"); getstrnwarn("slprofile",slprofile); /* Check for external PE table ***********************/ init_tablepar("pelist"); // Initialize pelist parameter if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); writetabletopar(t1,"pelist"); // Write t1 table to pelist parameter table = 1; } /* RF Power & Bandwidth Calculations ******************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Initialize gradient structures *********************/ init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_dephase(&crush_grad,"crush"); init_slice_refocus(&ssr_grad,"ssr"); if (FP_LT(tcrushro,alfa)) tcrushro=alfa; init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_generic(&spoil_grad,"spoil",gspoil,tspoil); /* Gradient calculations ******************************/ calc_readout(&ro_grad, WRITE,"gro","sw","at"); ro_grad.m0ref *= grof; calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad,NOWRITE,"gpe","tpe"); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,"gss2"); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); calc_generic(&spoil_grad,WRITE,"",""); /* Make sure crushing in PE dimension does not refocus signal from 180 */ crushm0=fabs(gcrush*tcrush); pem0=0.0; gcrushp=0.0; if (pecrush) pem0=pe_grad.m0; calc_dephase(&crush_grad,WRITE,crushm0+pem0,"",""); gcrushr = crush_grad.amp*crushm0/crush_grad.m0; if (pecrush) gcrushp = crush_grad.amp; gcrushs = crush_grad.amp*crushm0/crush_grad.m0; /* Allow phase encode and read dephase to be separated from slice refocus */ if (sepRefocus) { /* Equalize read dephase and PE gradient durations */ calc_sim_gradient(&ror_grad,&pe_grad,&null_grad,0,WRITE); crushsign=-1; } else { if (slprofile[0] == 'y') { /* Combined slice refocusing and read dephasing, reverse gradient sign if ror > ssr integral */ refsign = (ss_grad.m0ref > ro_grad.m0ref) ? 1.0 : -1.0; ss_grad.m0ref -= ro_grad.m0ref; calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); } /* Equalize both refocus and PE gradient durations */ calc_sim_gradient(&ror_grad,&pe_grad,&ssr_grad,0,WRITE); } /* Create optional prepulse events ********************/ if (fsat[0] == 'y') create_fatsat(); if (sat[0] == 'y') create_satbands(); if (mt[0] == 'y') create_mtc(); if (ir[0] == 'y') create_inversion_recovery(); if (diff[0] == 'y') init_diffusion(&diffusion,&diff_grad,"diff",gdiff,tdelta); sgl_error_check(sglerror); /* Min TE *********************************************/ te = granularity(te,2*GRADIENT_RES); /* tau1, tau2 are the sum of events in each half echo period */ /* tau1, tau2 include a GRADIENT_RES as this is minimum delay time */ tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + 2*GRADIENT_RES; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + ro_grad.timeToEcho + GRADIENT_RES; if (sepRefocus) tau2 += ror_grad.duration; temin = 2*MAX(tau1,tau2); /* Diffusion ******************************************/ if (diff[0] == 'y') { /* granulate tDELTA */ tDELTA = granularity(tDELTA,GRADIENT_RES); /* taudiff is the duration of events between diffusion gradients */ taudiff = ss2_grad.duration + 2*crush_grad.duration + GRADIENT_RES; /* set minimum diffusion structure requirements for gradient echo: taudiff, tDELTA, te and minte[0] */ set_diffusion(&diffusion,taudiff,tDELTA,te,minte[0]); /* set additional diffusion structure requirements for spin echo: tau1 and tau2 */ set_diffusion_se(&diffusion,tau1,tau2); /* calculate the diffusion structure delays. address &temin is required in order to update temin accordingly */ calc_diffTime(&diffusion,&temin); } /* TE delays ******************************************/ if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (FP_LT(te,temin)) { abort_message("TE too short, minimum TE = %.3f ms\n",temin*1000); } te_delay1 = te/2 - tau1 + GRADIENT_RES; te_delay2 = te/2 - tau2 + GRADIENT_RES; if (navigator[0] == 'y') { /* tau1, tau2 are the sum of events in each half echo period */ tau1 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + ro_grad.timeToEcho; if (FP_GT(tau1,tau2)) { te_delay3 = GRADIENT_RES; te_delay4 = tau1-tau2+GRADIENT_RES; } else { te_delay3 = tau2-tau1+GRADIENT_RES; te_delay4 = GRADIENT_RES; } navTime = te_delay3 + ss2_grad.duration + 2*crush_grad.duration + ro_grad.duration + te_delay4 + 2*GRADIENT_RES; } /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Min TR *********************************************/ trmin = ss_grad.rfCenterFront + te + ro_grad.timeFromEcho + pe_grad.duration + 2*GRADIENT_RES; /* Increase TR if any options are selected ************/ if (spoilflag[0] == 'y') trmin += spoil_grad.duration; if (navigator[0] == 'y') trmin += navTime; if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (ticks > 0) trmin += GRADIENT_RES; /* Adjust for all slices ******************************/ trmin *= ns; /* Inversion recovery *********************************/ if (ir[0] == 'y') { /* tauti is the additional time beyond IR component to be included in ti */ /* satTime, fsatTime and mtTime all included as those modules will be after IR */ tauti = satTime + fsatTime + mtTime + GRADIENT_RES + ss_grad.rfCenterFront; /* calc_irTime checks ti and returns the time of all IR components */ trmin += calc_irTime(tauti,trmin,mintr[0],tr,&trtype); } if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("TR too short, minimum TR = %.3f ms\n",trmin*1000); } /* TR delay *******************************************/ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Calculate B values *********************************/ if (ix == 1) { /* Calculate bvalues according to main diffusion gradients */ calc_bvalues(&diffusion,"dro","dpe","dsl"); /* Add components from additional diffusion encoding imaging gradients peculiar to this sequence */ /* Initialize variables */ dgro = 0.5*(ror_grad.duration+ro_grad.timeToEcho); Gro = ro_grad.m0ref/dgro; Dgro = dgro; if (!sepRefocus) Dgro = te-ss_grad.rfCenterBack-ro_grad.timeToEcho; dgss = 0.5*(ss_grad.rfCenterBack+ssr_grad.duration); Gss = ss_grad.m0ref/dgss; Dgss = dgss; dgss2 = ss2_grad.duration/2; Dgss2 = dgss2; dcrush = crush_grad.duration-crush_grad.tramp; Dcrush = crush_grad.duration+ss2_grad.duration; for (i = 0; i < diffusion.nbval; i++) { /* set droval, dpeval and dslval */ set_dvalues(&diffusion,&droval,&dpeval,&dslval,i); /* Readout */ diffusion.bro[i] += bval(Gro,dgro,Dgro); diffusion.bro[i] += bval(crushsign*gcrushr,dcrush,Dcrush); diffusion.bro[i] += bval_nested(gdiff*droval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); if (!sepRefocus) { diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,gdiff*droval,tdelta,tDELTA); diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,crushsign*gcrushr,dcrush,Dcrush); } /* Phase */ if (pecrush) { diffusion.bpe[i] += bval(gcrushp,dcrush,Dcrush); diffusion.bpe[i] += bval_nested(gdiff*dpeval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); } /* Slice */ diffusion.bsl[i] += bval(Gss,dgss,Dgss); diffusion.bsl[i] += bval(gcrushs,dcrush,Dcrush); diffusion.bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gcrushs,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); if (pecrush) diffusion.brp[i] += bval_cross(gdiff*droval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); if (!sepRefocus) { diffusion.brp[i] += bval_cross(Gro,dgro,Dgro,gdiff*dpeval,tdelta,tDELTA); if (pecrush) diffusion.brp[i] += bval_cross(Gro,dgro,Dgro,gcrushp,dcrush,Dcrush); } /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval2(crushsign*gcrushr,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,crushsign*gcrushr,dcrush,Dcrush); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); if (!sepRefocus) { diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gdiff*dslval,tdelta,tDELTA); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gcrushs,dcrush,Dcrush); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,ss2_grad.ssamp,dgss2,Dgss2); } /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,gcrushs,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); if (pecrush) { diffusion.bsp[i] += bval2(gcrushs,gcrushp,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,gcrushp,dcrush,Dcrush); diffusion.bsp[i] += bval_cross(gcrushp,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); } } /* End for-all-directions */ /* Write the values */ write_bvalues(&diffusion,"bval","bvalue","max_bval"); } /* Generate phase-ramped pulses ***********************/ offsetlist(pss,ss_grad.ssamp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shape90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shape180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* Set pe_steps for profile or full image *************/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&null_grad); F_initval(pe_steps/2.0,vpe_offset); /* Shift DDR for pro **********************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *******************/ if (ssc<0) { if (seqcon[2] == 'c') g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*arraydim - ssc*pe_steps*arraydim)); } else g_setExpTime(trmean*ntmean*pe_steps*arraydim + tr*ssc); /* Slice profile **************************************/ if (slprofile[0] == 'y' && !sepRefocus) ror_grad.amp = 0; /* Set phase cycle table ******************************/ if (sepRefocus) settable(t2,1,ph180); // Phase encode is just before readout else settable(t2,2,ph180); /* PULSE SEQUENCE *************************************/ status(A); // Set status A rotate(); // Set gradient rotation according to psi, phi and theta triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); // Set spectrometer frequency delay(GRADIENT_RES); // Delay for frequency setting initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s') assign(zero,vssc); // Zero for standard peloop assign(one,vacquire); // real-time acquire flag setacqvar(vacquire); // Turn on acquire when vacquire is zero /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); if (trtype) delay(ns*tr_delay); // relaxation delay /* Compressed steady-states: 1st array & transient, all arrays if ssc is negative */ if ((ix > 1) && (ssc > 0)) assign(zero,vssc); sub(vpe_ctr,vssc,vpe_ctr); // vpe_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's') assign(zero,vacquire); // Always acquire for non-compressed loop else { ifzero(vpe_ctr); assign(zero,vacquire); // Start acquiring when vpe_ctr reaches zero endif(vpe_ctr); } /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_mult); else { ifzero(vacquire); sub(vpe_ctr,vpe_offset,vpe_mult); elsenz(vacquire); sub(zero,vpe_offset,vpe_mult); // Hold PE mult at initial value for steady states endif(vacquire); } /* Phase cycle ****************************************/ getelem(t2,vpe_ctr,vph180); // For phase encoding with slice rephase add(oph,vph180,vph180); // 180 deg pulse phase alternates +/- 90 from receiver mod2(ct,vph2); dbl(vph2,vph2); add(vph180,vph2,vph180); // Alternate phase for 180 on odd transients /* Begin multislice loop ******************************/ msloop(seqcon[1],ns,vms_slices,vms_ctr); if (!trtype) delay(tr_delay); // Relaxation delay if (ticks > 0) { modn(vms_ctr,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(GRADIENT_RES); elsenz(vtest); delay(GRADIENT_RES); endif(vtest); } sp1on(); delay(GRADIENT_RES); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (ir[0] == 'y') inversion_recovery(); if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* Slice select RF pulse ******************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shape90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Slice refocus gradient *****************************/ if (sepRefocus) obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); else /* Include phase encode and readout dephase gradient if refocus gradients not separated */ pe_shapedgradient(pe_grad.name,pe_grad.duration,ror_grad.amp,0,-ssr_grad.amp*refsign,pe_grad.increment,vpe_mult,WAIT); if (diff[0] == 'y') { delay(diffusion.d1); diffusion_dephase(&diffusion,dro,dpe,dsl); delay(diffusion.d2); } else delay(te_delay1); /* Refocusing RF pulse ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(GRADIENT_RES); obl_shapedgradient(crush_grad.name,crush_grad.duration,crushsign*gcrushr,gcrushp,gcrushs,WAIT); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shape180,ss2_grad.rfDuration,vph180,rof2,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); obl_shapedgradient(crush_grad.name,crush_grad.duration,crushsign*gcrushr,gcrushp,gcrushs,WAIT); if (diff[0] == 'y') { delay(diffusion.d3); diffusion_rephase(&diffusion,dro,dpe,dsl); delay(diffusion.d4); } else delay(te_delay2); /* Readout dephase, phase encode & readout gradients **/ roff = -poffset(pro,ro_grad.roamp); // incase inverted navigator is acquired if (slprofile[0] == 'y') { /* Readout gradient only if refocus gradients not separated */ if (sepRefocus) obl_shapedgradient(ror_grad.name,ror_grad.duration,0,0,-ror_grad.amp,WAIT); obl_shapedgradient(ro_grad.name,ro_grad.duration,0,0,ro_grad.amp,NOWAIT); } else { /* Readout gradient only if refocus gradients not separated */ if (sepRefocus) pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,0,-pe_grad.increment,vpe_mult,WAIT); obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); } /* Acquisition ****************************************/ delay(ro_grad.atDelayFront-alfa); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); /* Rewind Phase encoding ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,vpe_mult,WAIT); /* Navigator acquisition ******************************/ if (navigator[0] == 'y') { delay(te_delay3); obl_shapedgradient(crush_grad.name,crush_grad.duration,-crushsign*gcrushr,0,-gcrushs,WAIT); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shape180,ss2_grad.rfDuration,vph180,rof2,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); obl_shapedgradient(crush_grad.name,crush_grad.duration,-crushsign*gcrushr,0,-gcrushs,WAIT); delay(te_delay4); obl_shapedgradient(ro_grad.name,ro_grad.duration,navsign*ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); } if (spoilflag[0] == 'y') { obl_shapedgradient(spoil_grad.name,spoil_grad.duration,navsign*spoil_grad.amp,0,spoil_grad.amp,WAIT); } endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vpe_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); /* Duty cycle *****************************************/ calc_grad_duty(tr); }
pulsesequence() { /* Internal variable declarations *************************/ double freq90[MAXNSLICE],freq180[MAXNSLICE],freqIR[MAXNSLICE]; int shape90=0, shape180=0, shapeIR=0; double te_delay1, te_delay2, tr_delay, ti_delay = 0; double del1=0, del2=0, del3=0, del4=0; double tau1=0, tau2=0, difftime=0, tetime=0; int table=0; /* Diffusion parameters */ #define MAXDIR 1024 /* Will anybody do more than 1024 directions or b-values? */ double roarr[MAXDIR], pearr[MAXDIR], slarr[MAXDIR]; int nbval, /* Total number of bvalues*directions */ nbro, nbpe, nbsl, i; double bro[MAXDIR], bpe[MAXDIR], bsl[MAXDIR], /* b-values along RO, PE, SL */ brs[MAXDIR], brp[MAXDIR], bsp[MAXDIR], /* and the cross-terms */ btrace[MAXDIR], /* and the trace */ max_bval=0, dcrush, dgss2, /* "delta" for crusher and gss2 gradients */ Dro, Dcrush, Dgss2; /* "DELTA" for readout, crusher and gss2 gradients */ /* Real-time variables ************************************/ int vpe_steps = v1; int vpe_ctr = v2; int vms_slices = v3; int vms_ctr = v4; int vpe_offset = v5; int vpe_index = v6; int vph180 = v7; // Phase of 180 pulse int vph2 = v8; // alternate phase of 180 on odd transients /* Initialize paramaters *********************************/ init_mri(); /* Check for external PE table ***************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } if ((diff[0] == 'y') && (gcrush < 4)) warn_message("Advisory: set gcrush to higher value to avoid image artifacts"); /* Initialize gradient structures *************************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); init_rf(&p2_rf,p2pat,p2,flip2,rof2,rof2); init_slice(&ss_grad,"ss",thk); init_slice_butterfly(&ss2_grad,"ss2",thk*1.1,gcrush,tcrush); init_slice_refocus(&ssr_grad,"ssr"); init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); /* RF Calculations ****************************************/ calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); if (p2_rf.header.rfFraction != 0.5) abort_message("RF pulse for refocusing (%s) must be symmetric",p2pat); /* Gradient calculations **********************************/ calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,"gss2"); calc_slice_refocus(&ssr_grad, &ss_grad, NOWRITE,"gssr"); calc_readout(&ro_grad, WRITE, "gro","sw","at"); ro_grad.m0ref *= grof; calc_readout_refocus(&ror_grad, &ro_grad, NOWRITE, "gror"); calc_phase(&pe_grad, NOWRITE, "gpe","tpe"); /* Equalize refocus and PE gradient durations *************/ calc_sim_gradient(&ror_grad, &pe_grad, &ssr_grad,0,WRITE); /* Set up diffusion gradient */ if (diff[0] == 'y') { init_generic(&diff_grad,"diff",gdiff,tdelta); calc_generic(&diff_grad,NOWRITE,"",""); /* adjust duration, so tdelta is from start ramp up to start ramp down */ if (ix == 1) diff_grad.duration += diff_grad.tramp; calc_generic(&diff_grad,WRITE,"",""); } /* Min TE *************************************************/ tau1 = ss_grad.rfCenterBack + pe_grad.duration + 4e-6 + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + ror_grad.duration + ro_grad.timeToEcho + alfa; temin = 2*(MAX(tau1,tau2) + 2*4e-6); /* have at least 4us between gradient events */ /* Calculate te_delays with the current TE, then later see how diffusion fits */ if ((minte[0] == 'y') || (te < temin)) { te_delay1 = temin/2 - tau1; te_delay2 = temin/2 - tau2; } else { te_delay1 = te/2 - tau1; te_delay2 = te/2 - tau2; } if (diff[0] =='y') { /* Is tDELTA long enough for RF refocusing gradient? */ if (tDELTA < diff_grad.duration + ss2_grad.duration) abort_message("DELTA too short, increase to %.2fms", (diff_grad.duration + ss2_grad.duration)*1000+0.005); /* Is tDELTA too long for TE dead time? */ difftime = tDELTA + diff_grad.duration; // tDELTA + front & back half diff_grad tetime = ss2_grad.duration + te_delay1 + te_delay2; if (difftime > tetime) { temin += (difftime - tetime); } } /* We now know the minimum TE incl. diffusion */ if (minte[0] == 'y') { te = temin; putvalue("te",ceil(te*1e6)*1e-6); /* round up to nearest us */ } if (te < temin) { if (diff[0] == 'n') { abort_message("TE too short. Minimum TE = %.2fms\n",temin*1000); } else { abort_message("TE too short, increase to %.2fms or reduce DELTA to %.2fms", temin*1000,(tetime-diff_grad.duration)*1000); } } te_delay1 = te/2 - tau1; te_delay2 = te/2 - tau2; /* Set up delays around diffusion gradients */ /* RF1 - del1 - diff - del2 - RF2 - del3 - diff - del4 - ACQ */ if (diff[0] == 'y') { del1 = (tetime - difftime)/2; del4 = del1; del2 = te_delay1 - diff_grad.duration; del3 = te_delay2 - diff_grad.duration; if (del3 < 0.0) { // shift diff block to right del1 += del3; del2 -= del3; del4 -= del3; del3 = 0; } else if (del2 < 0.0) { // shift diff block to left del1 -= del2; del3 -= del2; del4 += del2; del2 = 0; } } else { /* No diffusion */ del1 = 0; del3 = 0; del2 = te_delay1; del4 = te_delay2; } /* Min TR *************************************************/ trmin = (ss_grad.duration - ss_grad.rfCenterBack) + te + ro_grad.timeFromEcho; if (navigator[0] == 'y') trmin += (pe_grad.duration + ro_grad.duration); /* Optional prepulse calculations *************************/ if (sat[0] == 'y') { create_satbands(); trmin += satTime; } if (fsat[0] == 'y') { create_fatsat(); trmin += fsatTime; } if (mt[0] == 'y') { create_mtc(); trmin += mtTime; } if (ir[0] == 'y') { init_rf(&ir_rf,pipat,pi,flipir,rof2,rof2); calc_rf(&ir_rf,"tpwri","tpwrif"); init_slice_butterfly(&ssi_grad,"ssi",thk,gcrushir,tcrushir); calc_slice(&ssi_grad,&ir_rf,WRITE,"gssi"); tau1 = ss_grad.duration - ss_grad.rfCenterBack; /* duration of ss_grad before RF center */ ti_delay = ti - (ssi_grad.rfCenterBack + tau1); if (ti_delay < 0) { abort_message("TI too short, Minimum TI = %.2fms\n",(ti-ti_delay)*1000); } irTime = ti + ssi_grad.duration - ssi_grad.rfCenterBack; /* time to add to TR */ trmin += irTime; trmin -= tau1; /* but subtract out ss_grad which was already included in TR */ } trmin *= ns; if (mintr[0] == 'y'){ tr = trmin + ns*4e-6; putvalue("tr",tr); } if (tr < trmin) { abort_message("TR too short. Minimum TR= %.2fms\n",trmin*1000); } tr_delay = (tr - trmin)/ns > 4e-6 ? (tr - trmin)/ns : 4e-6; /***************************************************/ /* CALCULATE B VALUES ******************************/ if (diff[0] == 'y') { /* Get multiplication factors and make sure they have same # elements */ /* All this is only necessary because putCmd only work for ix==1 */ nbro = (int) getarray("dro",roarr); nbval = nbro; nbpe = (int) getarray("dpe",pearr); if (nbpe > nbval) nbval = nbpe; nbsl = (int) getarray("dsl",slarr); if (nbsl > nbval) nbval = nbsl; if ((nbro != nbval) && (nbro != 1)) abort_message("%s: Number of directions/b-values must be the same for all axes (readout)",seqfil); if ((nbpe != nbval) && (nbpe != 1)) abort_message("%s: Number of directions/b-values must be the same for all axes (phase)",seqfil); if ((nbsl != nbval) && (nbsl != 1)) abort_message("%s: Number of directions/b-values must be the same for all axes (slice)",seqfil); if (nbro == 1) for (i = 1; i < nbval; i++) roarr[i] = roarr[0]; if (nbpe == 1) for (i = 1; i < nbval; i++) pearr[i] = pearr[0]; if (nbsl == 1) for (i = 1; i < nbval; i++) slarr[i] = slarr[0]; } else { nbval = 1; roarr[0] = 0; pearr[0] = 0; slarr[0] = 0; } for (i = 0; i < nbval; i++) { /* Readout */ Dro = ror_grad.duration; bro[i] = bval(gdiff*roarr[i],tdelta,tDELTA); bro[i] += bval(ro_grad.amp,ro_grad.timeToEcho,Dro); /* Slice */ dgss2 = Dgss2 = ss_grad.rfCenterFront; dcrush = tcrush; //"delta" for crusher part of butterfly Dcrush = dcrush + ss_grad.rfDuration; //"DELTA" for crusher bsl[i] = bval(gdiff*slarr[i],tdelta,tDELTA); bsl[i] += bval(gcrush,dcrush,Dcrush); bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush); bsl[i] += bval_nested(gdiff*slarr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); bsl[i] += bval_nested(gcrush,dcrush,Dcrush,ss2_grad.ssamp,dgss2,Dgss2); /* Phase */ bpe[i] = bval(gdiff*pearr[i],tdelta,tDELTA); /* Readout/Slice Cross-terms */ brs[i] = bval2(gdiff*roarr[i],gdiff*slarr[i],tdelta,tDELTA); brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush); brs[i] += bval_cross(gdiff*roarr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ brp[i] = bval2(gdiff*roarr[i],gdiff*pearr[i],tdelta,tDELTA); /* Slice/Phase Cross-terms */ bsp[i] = bval2(gdiff*slarr[i],gdiff*pearr[i],tdelta,tDELTA); bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA,gcrush,dcrush,Dcrush); bsp[i] += bval_cross(gdiff*pearr[i],tdelta,tDELTA,ss2_grad.ssamp,dgss2,Dgss2); btrace[i] = (bro[i]+bsl[i]+bpe[i]); if (max_bval < btrace[i]) { max_bval = (bro[i]+bsl[i]+bpe[i]); } } /* End for-all-directions */ putarray("bvalrr",bro,nbval); putarray("bvalpp",bpe,nbval); putarray("bvalss",bsl,nbval); putarray("bvalrp",brp,nbval); putarray("bvalrs",brs,nbval); putarray("bvalsp",bsp,nbval); putarray("bvalue",btrace,nbval); putvalue("max_bval",max_bval); /* Generate phase-ramped pulses: 90, 180, and IR */ offsetlist(pss,ss_grad.ssamp,0,freq90,ns,seqcon[1]); shape90 = shapelist(p1pat,ss_grad.rfDuration,freq90,ns,0,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shape180 = shapelist(p2pat,ss2_grad.rfDuration,freq180,ns,0,seqcon[1]); if (ir[0] == 'y') { offsetlist(pss,ssi_grad.ssamp,0,freqIR,ns,seqcon[1]); shapeIR = shapelist(pipat,ssi_grad.rfDuration,freqIR,ns,0,seqcon[1]); } /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&null_grad); initval(pe_steps/2.0,vpe_offset); sgl_error_check(sglerror); /* Return parameters to VnmrJ */ putvalue("rgss",ss_grad.tramp); //90 slice ramp if (ss2_grad.enableButterfly) { //180 slice ramps putvalue("rcrush",ss2_grad.crusher1RampToCrusherDuration); putvalue("rgss2",ss2_grad.crusher1RampToSsDuration); } else { putvalue("rgss2",ss2_grad.tramp); } if (ro_grad.enableButterfly) { putvalue("rgro",ro_grad.crusher1RampToSsDuration); } else { putvalue("rgro",ro_grad.tramp); //RO ramp } putvalue("tror",ror_grad.duration); //ROR duration putvalue("rgror",ror_grad.tramp); //ROR ramp putvalue("gpe",pe_grad.peamp); //PE max amp putvalue("gss",ss_grad.ssamp); putvalue("gro",ro_grad.roamp); g_setExpTime(tr*(nt*pe_steps*arraydim + ssc)); /* PULSE SEQUENCE *************************************/ rotate(); obsoffset(resto); roff = -poffset(pro,ro_grad.roamp); delay(4e-6); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); /* Read external kspace table if set ******************/ if (table) getelem(t1,vpe_ctr,vpe_index); else sub(vpe_ctr,vpe_offset,vpe_index); settable(t2,2,ph180); // initialize phase tables and variables getelem(t2,vpe_ctr,vph180); add(oph,vph180,vph180); // 180 deg pulse phase alternates +/- 90 from receiver mod2(ct,vph2); dbl(vph2,vph2); add(vph180,vph2,vph180); // Alternate phase for 180 on odd transients /* Begin multislice loop ******************************/ msloop(seqcon[1],ns,vms_slices,vms_ctr); if (ticks) { xgate(ticks); grad_advance(gpropdelay); } /* TTL scope trigger **********************************/ sp1on(); delay(5e-6); sp1off(); /* Prepulses ******************************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (mt[0] == 'y') mtc(); /* Optional IR pulse **********************************/ if (ir[0] == 'y') { obspower(ir_rf.powerCoarse); obspwrf(ir_rf.powerFine); delay(4e-6); obl_shapedgradient(ssi_grad.name,ssi_grad.duration,0,0,ssi_grad.amp,NOWAIT); delay(ssi_grad.rfDelayFront); shapedpulselist(shapeIR,ssi_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ssi_grad.rfDelayBack); delay(ti_delay); } /* Slice select RF pulse ******************************/ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(4e-6); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shape90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Phase encode, refocus, and dephase gradient ********/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,-ssr_grad.amp, pe_grad.increment,vpe_index,WAIT); delay(del1); // delay to start of first diffusion gradient if (diff[0] == 'y') { obl_shapedgradient(diff_grad.name,diff_grad.duration, diff_grad.amp*dro,diff_grad.amp*dpe,diff_grad.amp*dsl,WAIT); } delay(del2); // delay from end of diffusion to slice refocusing /* Refocusing RF pulse ********************************/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(4e-6); obl_shapedgradient(ss2_grad.name,ss2_grad.duration,0,0,ss2_grad.amp,NOWAIT); delay(ss2_grad.rfDelayFront); shapedpulselist(shape180,ss2_grad.rfDuration,vph180,rof2,rof2,seqcon[1],vms_ctr); delay(ss2_grad.rfDelayBack); delay(del3); // delay from slice refocusing to second diffusion gradient if (diff[0] == 'y') { obl_shapedgradient(diff_grad.name,diff_grad.duration, diff_grad.amp*dro,diff_grad.amp*dpe,diff_grad.amp*dsl,WAIT); } delay(del4); // delay from end of diffusion gradient to readout event /* Readout gradient and acquisition ********************/ roff = -poffset(pro,ro_grad.roamp); obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT); obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); /* Rewind Phase encoding ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0, pe_grad.increment,vpe_index,WAIT); if (navigator[0] == 'y') { roff = -poffset(pro,-ro_grad.roamp); obl_shapedgradient(ro_grad.name,ro_grad.duration,-ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); } /* Relaxation delay ***********************************/ delay(tr_delay); endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vpe_ctr); }
pulsesequence() { /* Internal variable declarations *************************/ double freqEx[MAXNSLICE]; double pespoil_amp,spoilMoment,maxgradtime,pe2_offsetamp=0.0,nvblock; double tetime,te_delay,tr_delay,perTime; int table=0,shapeEx=0,sepSliceRephase=0,image,blocknvs; char spoilflag[MAXSTR],perName[MAXSTR],slab[MAXSTR]; /* Real-time variables used in this sequence **************/ int vpe_steps = v1; // Number of PE steps int vpe_ctr = v2; // PE loop counter int vpe_offset = v3; // PE/2 for non-table offset int vpe_mult = v4; // PE multiplier, ranges from -PE/2 to PE/2 int vper_mult = v5; // PE rewinder multiplier; turn off rewinder when 0 int vpe2_steps = v6; // Number of PE2 steps int vpe2_ctr = v7; // PE2 loop counter int vpe2_mult = v8; // PE2 multiplier int vpe2_offset = v9; // PE2/2 for non-table offset int vpe2r_mult = v10; // PE2 rewinder multiplier int vtrigblock = v11; // Number of PE steps per trigger block int vpe = v12; // Current PE step out of total PE*PE2 steps /* Initialize paramaters *********************************/ init_mri(); getstr("spoilflag",spoilflag); getstr("slab",slab); image = getval("image"); blocknvs = (int)getval("blocknvs"); nvblock = getval("nvblock"); if (!blocknvs) nvblock=1; // If blocked PEs for trigger not selected nvblock=1 trmin = 0.0; temin = 0.0; /* Check for external PE table ***************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } if (ns > 1) abort_message("No of slices must be set to one"); /* RF Calculations ****************************************/ init_rf(&p1_rf,p1pat,p1,flip1,rof1,rof2); /* hard pulse */ init_rf(&p2_rf,p2pat,p2,flip2,rof1,rof2); /* soft pulse */ calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); /* Gradient calculations **********************************/ if (slab[0] == 'y') { init_slice(&ss_grad,"ss",thk); init_slice_refocus(&ssr_grad,"ssr"); calc_slice(&ss_grad,&p2_rf,WRITE,"gss"); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); } if (FP_GT(tcrushro,0.0)) init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); else init_readout(&ro_grad,"ro",lro,np,sw); init_readout_refocus(&ror_grad,"ror"); calc_readout(&ro_grad,WRITE,"gro","sw","at"); ro_grad.m0ref *= grof; calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); init_phase(&pe_grad,"pe",lpe,nv); init_phase(&pe2_grad,"pe2",lpe2,nv2); calc_phase(&pe_grad,NOWRITE,"gpe","tpe"); if (!blocknvs) nvblock=1; calc_phase(&pe2_grad,NOWRITE,"gpe2",""); if (spoilflag[0] == 'y') { // Calculate spoil grad if spoiling is turned on init_dephase(&spoil_grad,"spoil"); // Optimized spoiler spoilMoment = ro_grad.acqTime*ro_grad.roamp; // Optimal spoiling is at*gro for 2pi per pixel spoilMoment -= ro_grad.m0def; // Subtract partial spoiling from back half of readout calc_dephase(&spoil_grad,WRITE,spoilMoment,"gspoil","tspoil"); } /* Is TE long enough for separate slab refocus? ***********/ maxgradtime = MAX(ror_grad.duration,MAX(pe_grad.duration,pe2_grad.duration)); if (spoilflag[0] == 'y') maxgradtime = MAX(maxgradtime,spoil_grad.duration); tetime = maxgradtime + alfa + ro_grad.timeToEcho + 4e-6; if (slab[0] == 'y') { tetime += ss_grad.rfCenterBack + ssr_grad.duration; if ((te >= tetime) && (minte[0] != 'y')) { sepSliceRephase = 1; // Set flag for separate slice rephase } else { pe2_grad.areaOffset = ss_grad.m0ref; // Add slab refocus on pe2 axis calc_phase(&pe2_grad,NOWRITE,"gpe2",""); // Recalculate pe2 to include slab refocus } } /* Equalize refocus and PE gradient durations *************/ pespoil_amp = 0.0; perTime = 0.0; if ((perewind[0] == 'y') && (spoilflag[0] == 'y')) { // All four must be single shape if (ror_grad.duration > spoil_grad.duration) { // calc_sim first with ror calc_sim_gradient(&pe_grad,&pe2_grad,&ror_grad,tpemin,WRITE); calc_sim_gradient(&ror_grad,&spoil_grad,&null_grad,tpemin,NOWRITE); } else { // calc_sim first with spoil calc_sim_gradient(&pe_grad,&pe2_grad,&spoil_grad,tpemin,WRITE); calc_sim_gradient(&ror_grad,&spoil_grad,&null_grad,tpemin,NOWRITE); } strcpy(perName,pe_grad.name); perTime = pe_grad.duration; putvalue("tspoil",perTime); putvalue("gspoil",spoil_grad.amp); } else { // post-acquire shape will be either pe or spoil, but not both calc_sim_gradient(&ror_grad,&pe_grad,&pe2_grad,tpemin,WRITE); if ((perewind[0] == 'y') && (spoilflag[0] == 'n')) { // Rewinder, no spoiler strcpy(perName,pe_grad.name); perTime = pe_grad.duration; spoil_grad.amp = 0.0; putvalue("tpe",perTime); } else if ((perewind[0] == 'n') && (spoilflag[0] == 'y')) { // Spoiler, no rewinder strcpy(perName,spoil_grad.name); perTime = spoil_grad.duration; pespoil_amp = spoil_grad.amp; // Apply spoiler on PE & PE2 axis if no rewinder } } if (slab[0] == 'y') pe2_offsetamp = sepSliceRephase ? 0.0 : pe2_grad.offsetamp; // pe2 slab refocus /* Create optional prepulse events ************************/ if (sat[0] == 'y') create_satbands(); if (fsat[0] == 'y') create_fatsat(); sgl_error_check(sglerror); // Check for any SGL errors /* Min TE ******************************************/ tetime = pe_grad.duration + alfa + ro_grad.timeToEcho; if (slab[0] == 'y') { tetime += ss_grad.rfCenterBack; tetime += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event } else if (ws[0] == 'y') tetime += p2/2.0 + rof2; /* soft pulse */ else tetime += p1/2.0 + rof2; /* hard pulse */ temin = tetime + 4e-6; // Ensure that te_delay is at least 4us if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (te < temin) { abort_message("TE too short. Minimum TE= %.2fms\n",temin*1000+0.005); } te_delay = te - tetime; /* Min TR ******************************************/ trmin = te_delay + pe_grad.duration + ro_grad.duration + perTime; if (slab[0] == 'y') { trmin += ss_grad.duration; trmin += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event } else if (ws[0] == 'y') trmin += p2 +rof1 + rof2; /* soft pulse */ else trmin += p1 +rof1 + rof2; /* hard pulse */ trmin += 8e-6; /* Increase TR if any options are selected *********/ if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (ticks > 0) trmin += 4e-6; if (mintr[0] == 'y') { tr = trmin; putvalue("tr",tr); } if (FP_LT(tr,trmin)) { abort_message("TR too short. Minimum TR = %.2fms\n",trmin*1000+0.005); } /* Calculate tr delay */ tr_delay = granularity(tr-trmin,GRADIENT_RES); if(slab[0] == 'y') { /* Generate phase-ramped pulses: 90 */ offsetlist(pss,ss_grad.ssamp,0,freqEx,ns,seqcon[1]); shapeEx = shapelist(p1pat,ss_grad.rfDuration,freqEx,ns,ss_grad.rfFraction,seqcon[1]); } /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&null_grad); F_initval(pe_steps/2.0,vpe_offset); pe2_steps = prep_profile(profile[1],nv2,&pe2_grad,&null_grad); F_initval(pe2_steps/2.0,vpe2_offset); assign(zero,oph); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *******************/ g_setExpTime(tr*(nt*pe_steps*pe2_steps)); /* PULSE SEQUENCE *************************************/ status(A); rotate(); triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); delay(4e-6); /* trigger */ if (ticks > 0) F_initval((double)nvblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop2(seqcon[3],pe2_steps,vpe2_steps,vpe2_ctr); peloop(seqcon[2],pe_steps,vpe_steps,vpe_ctr); delay(tr_delay); // relaxation delay sub(vpe_ctr,vpe_offset,vpe_mult); sub(vpe2_ctr,vpe2_offset,vpe2_mult); mult(vpe2_ctr,vpe_steps,vpe); add(vpe_ctr,vpe,vpe); /* PE rewinder follows PE table; zero if turned off ***/ if (perewind[0] == 'y') { assign(vpe_mult,vper_mult); assign(vpe2_mult,vpe2r_mult); } else { assign(zero,vper_mult); assign(zero,vpe2r_mult); } if (ticks > 0) { modn(vpe,vtrigblock,vtest); ifzero(vtest); // if the beginning of an trigger block xgate(ticks); grad_advance(gpropdelay); delay(4e-6); elsenz(vtest); delay(4e-6); endif(vtest); } sp1on(); delay(4e-6); sp1off(); // Scope trigger /* Prepulse options ***********************************/ if (sat[0] == 'y') satbands(); if (fsat[0] == 'y') fatsat(); if (slab[0] == 'y') { obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(4e-6); obl_shapedgradient(ss_grad.name,ss_grad.duration,0,0,ss_grad.amp,NOWAIT); delay(ss_grad.rfDelayFront); shapedpulselist(shapeEx,ss_grad.rfDuration,zero,rof1,rof2,seqcon[1],zero); delay(ss_grad.rfDelayBack); if (sepSliceRephase) { obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); delay(te_delay + tau); /* tau is current B0 encoding delay */ } } else { obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(4e-6); if (ws[0] == 'y') shapedpulse(p2pat,p2,zero,rof1,rof2); /* soft CS pulse */ else shapedpulse(p1pat,p1,zero,rof1,rof2); /* hard pulse */ delay(te_delay + tau); /* tau is current B0 encoding delay */ } pe2_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp*image,0,-pe2_offsetamp, -pe_grad.increment,-pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); if ((slab[0] == 'y') && !sepSliceRephase) delay(te_delay + tau); /* tau is current B0 encoding delay */ /* Readout gradient and acquisition ********************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp*image,0,0,NOWAIT); delay(ro_grad.atDelayFront); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); /* Rewind / spoiler gradient *********************************/ if (perewind[0] == 'y' || (spoilflag[0] == 'y')) { pe2_shapedgradient(perName,perTime,spoil_grad.amp,pespoil_amp,pespoil_amp, pe_grad.increment,pe2_grad.increment,vper_mult,vpe2r_mult,WAIT); } endpeloop(seqcon[2],vpe_ctr); endpeloop(seqcon[3],vpe2_ctr); }
pulsesequence() { /***** Internal variable declarations *****/ int shapelist1,shapelist2,shapelist3; /* pulse shapes (lists) */ double freq1,freq2,freq3,ws_delta; double rprof,pprof,sprof; double restol, resto_local,csd_ppm; char profile_ovs[MAXSTR]; char profile_vox[MAXSTR]; int wsfirst; //wsfirst makes ws unit to be exececuted first int isis; int counter,noph; char autoph[MAXSTR],pcflag[MAXSTR]; /* sequence timing variables */ double te_delay1, te_delay2, newdelay,tr_delay, tm_delay; double tau1=0, tau2=0; /* Extra crushers */ double gcrushtm,tcrushtm; double ky; double vox3_cr, vox3r_cr; double gcrush_end, tcrush_end; /*extra ws pulse flag*/ char ws_tm[MAXSTR]; double wsflipftm; double tmwstpwr,tmwstpwrf; init_mri(); noph=(int)getval("noph"); isis=(int)getval("isis"); int inv1[32]= {0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3};//excitation pulse int inv2[32]= {0, 0, 1, 1, 2, 2, 3, 3, 0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3, 0, 0, 1, 1, 2, 2, 3, 3, 0, 0}; //refocusing pulse int inv3[32]= {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3};//inversion pulse int phrec[32]= {0, 2, 2, 0, 2, 0, 0, 2, 0, 2, 2, 0, 2, 0, 0, 2, 1, 3, 3, 1, 3, 1, 1, 3, 1, 3, 3, 1, 3, 1, 1, 3};// rec phase int phrec0[32]= {0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1};// rec phase for non-isis /***** Real-time variables used in this sequence *****/ int vinv1 = v1; // on/off flag first inversion pulse int vms = v5; // dummy shapedpulselist slice counter (= one) get_ovsparameters(); get_wsparameters(); rprof = getval("rprof"); pprof = getval("pprof"); sprof = getval("sprof"); ky=getval("ky"); getstr("autoph",autoph); getstr("pcflag",pcflag); getstr("profile_ovs",profile_ovs); getstr("profile_vox",profile_vox); wsfirst=(int)getval("wsfirst"); restol=getval("restol"); //local frequency offset roff=getval("roff"); //receiver offset csd_ppm=getval("csd_ppm"); //chemical shift displacement factor gcrushtm = getval("gcrushtm"); tcrushtm = getval("tcrushtm"); wsflipftm = getval("wsflipftm"); getstr("ws_tm",ws_tm); ws_delta=getval("ws_delta"); vox3_cr=1000000; /***** RF power calculations *****/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2); shape_rf(&p2_rf,"p2",p2pat,p2,flip2,rof1,rof2); shape_rf(&p3_rf,"p3",p3pat,p3,flip3,rof1,rof2); shape_rf(&p4_rf,"p4",p4pat,p4,flip4,rof1,rof2); p4_rf.flipmult=wsflipftm; calc_rf(&p1_rf,"tpwr1","tpwr1f"); calc_rf(&p2_rf,"tpwr2","tpwr2f"); calc_rf(&p3_rf,"tpwr3","tpwr3f"); calc_rf(&p4_rf,"tpwr4","tpwr4f"); // wsfpwrtm=p4_rf.powerFine*wsflipftm; /* ws fine RF power */ trampfixed=trise; //rise time =trise tcrush=granularity(tcrush,GRADIENT_RES); //this is to avoid the granularity errors //if trampfixed is used, rise time needs to be checked if (trise*2>tcrush){ abort_message("tcrush too short. Minimum tcrush = %fms \n",1000*trise*2); } if (gcrush>gmax){ abort_message("gcrush too large. Max gcrush = %f \n",gmax*0.95); } init_slice(&vox1_grad,"vox1",vox1); init_slice(&vox2_grad,"vox2",vox2); init_slice_butterfly(&vox3_crush,"vox3_crush",vox3_cr,gcrush,tcrush); init_slice_butterfly(&vox3r_crush,"vox3r_crush",vox3_cr,gcrush,tcrush); init_slice_butterfly(&vox3_grad,"vox3",vox3,gcrush,tcrush); init_generic(&tmcrush_grad,"tmcrush",gcrushtm,tcrushtm); //crusher grad during tm if (profile_vox[0] == 'y') { init_readout_butterfly(&ro_grad,"ro",lro,np,sw,gcrushro,tcrushro); init_readout_refocus(&ror_grad,"ror"); } /***** Gradient calculations *****/ calc_slice(&vox1_grad,&p1_rf,WRITE,"vox1_grad"); calc_slice(&vox2_grad,&p2_rf,WRITE,"vox2_grad"); calc_slice(&vox3_grad,&p3_rf,NOWRITE,""); calc_slice(&vox3_crush,&p3_rf,WRITE,"vox3_crush"); calc_slice(&vox3r_crush,&p3_rf,NOWRITE,""); vox3r_crush.crusher1Moment0 -= vox2_grad.m0ref; //only now can re-calculate the moment vox3r_crush.crusher1CalcFlag=AMPLITUDE_FROM_MOMENT_DURATION_RAMP; calc_slice(&vox3r_crush,&p3_rf,WRITE,"vox3r_crush"); vox3_grad.crusher2Moment0 *= vox3_grad.m0def/vox3_grad.m0ref*ky; //only now can re-calculate the moment vox3_grad.crusher2CalcFlag=AMPLITUDE_FROM_MOMENT_DURATION_RAMP; calc_slice(&vox3_grad,&p3_rf,WRITE,"vox3_grad"); calc_generic(&tmcrush_grad,WRITE,"",""); if (profile_vox[0] == 'y') { calc_readout(&ro_grad,WRITE,"gro","sw","at"); putvalue("gro",ro_grad.roamp); // RO grad calc_readout_refocus(&ror_grad,&ro_grad,WRITE,"gror"); putvalue("tror",ror_grad.duration); // ROR duration } if (profile_ovs[0]=='y'){ if (rprof==1) { vox1_grad.amp=0; } else if(pprof==1) { vox2_grad.amp=0; } else if(sprof==1) { vox3_grad.amp=0; } } /***** Check nt is a multiple of 2 *****/ if (ix == 1) { if ((int)nt%2 != 0) text_message("WARNING: SPECIAL requires 2 steps. Set nt as a multiple of 2\n"); } /* Optional Outer Volume Suppression */ if (ovs[0] == 'y') create_ovsbands(); if (sat[0] == 'y') create_satbands(); /* Optional Water Suppression */ if (ws[0] == 'y') create_watersuppress(); /***** Set up frequency offset pulse shape list *****/ offsetlist(&pos1,vox1_grad.ssamp,0,&freq1,1,'s'); offsetlist(&pos2,vox2_grad.ssamp,0,&freq2,1,'s'); offsetlist(&pos3,vox3_grad.ssamp,0,&freq3,1,'s'); if (profile_ovs[0]=='y'&& sprof==1) freq3=0.0; if (profile_ovs[0]=='y'&& pprof==1) freq2=0.0; if (profile_ovs[0]=='y'&& rprof==1) freq1=0.0; freq1=freq1-csd_ppm*sfrq; freq2=freq2-csd_ppm*sfrq; freq3=freq3-csd_ppm*sfrq; shapelist1 = shapelist(p1_rf.pulseName,vox1_grad.rfDuration,&freq1,1,vox1_grad.rfFraction,'s'); shapelist2 = shapelist(p2_rf.pulseName,vox2_grad.rfDuration,&freq2,1,vox2_grad.rfFraction,'s'); shapelist3 = shapelist(p3_rf.pulseName,vox3_grad.rfDuration,&freq3,1,vox3_grad.rfFraction,'s'); /* Calculate delta from resto to include local frequency line + chemical shift offset */ resto_local=resto-restol; /* Frequency offsets */ if (profile_vox[0] == 'y') { /* Shift DDR for pro ************************************/ roff = -poffset(pro,ro_grad.roamp); } /* Set tables */ /* Real time variables for inversion pulses */ settable(t1,noph,inv1); settable(t2,noph,inv2); settable(t3,noph,inv3); /* Phase cycle for excitation pulse and receiver */ if (isis!=1) settable(t4,noph,phrec0); else settable(t4,noph,phrec); /* shapedpulselist variable */ assign(one,vms); /* Put gradient information back into VnmrJ parameters */ putvalue("gvox1",vox1_grad.ssamp); putvalue("gvox2",vox2_grad.ssamp); putvalue("gvox3",vox3_grad.ssamp); putvalue("rgvox1",vox1_grad.tramp); putvalue("rgvox2",vox2_grad.tramp); putvalue("rgvox3",vox3_grad.tramp); sgl_error_check(sglerror); if (ss<0) g_setExpTime(trmean*(nt-ss)*arraydim); else g_setExpTime(tr*(ntmean*arraydim+ss)); /* PULSE SEQUENCE *************************************/ /* Real time variables for inversion pulses */ counter=(double)nt*(ix-1); if (autoph[0] == 'n') counter=0.0; initval(counter,v11); initval(noph,v13); //v13=number of phase cycling steps add(v11,ctss,v12); //v12=counter modn(v12,v13,v12); //v12 runs from 1:v13 getelem(t1,v12,v8); /* 90 DEG. SPIN ECHO PULSE */ getelem(t2,v12,v9); /* 180 DEG. SPIN ECHO P. */ getelem(t3,v12,v10); /* ISIS 180 DEG. ADIAB. PULSE */ getelem(t4,v12,oph); /*RCVR PHASE*/ mod2(v12,vinv1); // this controls 1D isis on, off, on, of... up to noph(=32) /****************************************************/ /* Sequence Timing **********************************/ /****************************************************/ /* Min TE ******************************************/ tau1 = vox2_grad.rfCenterBack + vox3_grad.rfCenterFront; tau2 = vox3_grad.rfCenterBack+alfa; temin = 2*(MAX(tau1,tau2) + 4e-6); /* have at least 4us between gradient events */ if (minte[0] == 'y') { te = temin; putvalue("te",te); } else if (te < temin) { abort_message("TE too short. Minimum TE = %.2fms\n",temin*1000); } te_delay1 = te/2 - tau1; te_delay2 = te/2 - tau2; printf("te delay1 is %f", te_delay1); printf("te delay2 is %f", te_delay2); /***************************************************/ /* Min TM ******************************************/ if (ws_tm[0] == 'y') { tau1 = vox1_grad.rfCenterBack + rof1+rof2+p4_rf.rfDuration+tmcrush_grad.duration + 4e-6 + vox2_grad.rfCenterFront; } else tau1 = vox1_grad.rfCenterBack + rof2+tmcrush_grad.duration + 4e-6 + vox2_grad.rfCenterFront; tmmin = tau1 + 4e-6; /* have at least 4us between gradient events */ if (mintm[0] == 'y') { tm = tmmin; putvalue("tm",tm); } else if (tm < tmmin) { abort_message("TM too short. Minimum TM = %.2fms\n",tmmin*1000); } tm_delay = (tm - tau1); /* Relaxation delay ***********************************/ /***** Min TR *****/ trmin = vox1_grad.rfCenterFront + tm + te+alfa + at + 20e-6; if (profile_vox[0] == 'y') trmin += ror_grad.duration + ro_grad.duration - at; if (ws[0] == 'y') trmin += wsTime; if (ovs[0] == 'y') trmin += ovsTime; if (sat[0] == 'y') trmin += satTime; if (mintr[0] == 'y') { tr = trmin; putCmd("setvalue('tr',%f,'current')\n",tr); } if ((trmin-tr) > 12.5e-9) { abort_message("tr too short. Minimum tr = %.2f ms\n",(trmin)*1000); } /***** Calculate TR delay *****/ tr_delay = tr - trmin; /**Sequence Begin**/ status(A); obsoffset(resto_local); delay(4e-6); set_rotation_matrix(vpsi,vphi,vtheta); if (ticks > 0) { xgate(ticks); grad_advance(gpropdelay); delay(4e-6); } /* TTL scope trigger **********************************/ sp1on(); delay(4e-6); sp1off(); /* Saturation bands ***********************************/ if (ovs[0] == 'y') ovsbands(); if (sat[0] == 'y') satbands(); /* Post OVS water suppression *************************/ if (ws[0] == 'y') watersuppress(); /* First inversion pulse *****/ if (isis >= 1){ /*for the ISIS pulse on,off,on,off... or on,on,on,on... */ obspower(p1_rf.powerCoarse); obspwrf(p1_rf.powerFine); delay(4e-6); if (isis == 1) /* for ISIS on,off,on,off,... */{ ifzero(vinv1); obl_shapedgradient(vox1_grad.name,vox1_grad.duration,vox1_grad.amp,0,0,NOWAIT); delay(vox1_grad.rfDelayFront); shapedpulselist(shapelist1,vox1_grad.rfDuration,v10,rof1,rof2,'s',vms); delay(vox1_grad.rfDelayBack); elsenz(vinv1); obl_shapedgradient(vox1_grad.name,vox1_grad.duration,vox1_grad.amp,0,0,WAIT); endif(vinv1); } else { /* for ISIS on,on,on,on...*/ obl_shapedgradient(vox1_grad.name,vox1_grad.duration,vox1_grad.amp,0,0,NOWAIT); delay(vox1_grad.rfDelayFront); shapedpulselist(shapelist1,vox1_grad.rfDuration,v10,rof1,rof2,'s',vms); delay(vox1_grad.rfDelayBack); } } else delay(vox1_grad.duration); //this is for isis off,off,off,off /* tm delay before excitation pulse *****/ /* Optional TM water suppression ***********************/ if (ws_tm[0] == 'y') { if (wsrf[0]=='y') { obspower(p4_rf.powerCoarse); obspwrf(p4_rf.powerFine); delay(4e-6); shapedpulseoffset(p4_rf.pulseName,p4_rf.rfDuration,zero,rof1,rof2,ws_delta); } else delay(p4_rf.rfDuration+rof1+rof2); } //end of ws_tm='y' condition delay(tm_delay); /* TM Gradient crusher ********************************/ obl_shapedgradient(tmcrush_grad.name,tmcrush_grad.duration,0,0,tmcrush_grad.amp,WAIT); /* 90 degree excitation pulse *****/ obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); delay(4e-6); obl_shapedgradient(vox2_grad.name,vox2_grad.duration,0,vox2_grad.amp,0,NOWAIT); delay(vox2_grad.rfDelayFront); shapedpulselist(shapelist2,vox2_grad.rfDuration,v8,rof1,rof2,'s',vms); delay(vox2_grad.rfDelayBack); delay(te_delay1); /* 180 degree pulse ********************************/ obspower(p3_rf.powerCoarse); obspwrf(p3_rf.powerFine); delay(4e-6); obl_shaped3gradient (vox3_crush.name,vox3r_crush.name,vox3_grad.name,vox3_grad.duration,vox3_crush.amp,vox3r_crush.amp,vox3_grad.amp,NOWAIT); delay(vox3_grad.rfDelayFront); shapedpulselist(shapelist3,vox3_grad.rfDuration,v9,rof1,rof2,'s',vms); delay(vox3_grad.rfDelayBack); delay(te_delay2); //acquisition starts if (profile_vox[0] == 'y') { obl_shapedgradient(ror_grad.name,ror_grad.duration, -rprof*ror_grad.amp,-pprof*ror_grad.amp,-sprof*ror_grad.amp,WAIT); delay(4e-6); obl_shapedgradient(ro_grad.name,ro_grad.duration, rprof*ro_grad.amp,pprof*ro_grad.amp,sprof*ro_grad.amp,NOWAIT); delay(ro_grad.atDelayFront); startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); } else { startacq(alfa); acquire(np,1.0/sw); endacq(); } delay(tr_delay); }