void shape_rf (RF_PULSE_T *rf, char rfBase[MAX_STR], char rfName[MAX_STR], double pw, double flip, double rof1, double rof2) { if ((ix > 1) && !sglarray) { rf->flip = flip; return; } initRf(rf); strcpy(rf->pulseBase,rfBase); strcpy(rf->pulseName,rfName); strcpy(rf->rfcoil,rfcoil); rf->rfDuration = pw; rf->flip = flip; rf->flipmult = 1.0; rf->rof1 = rof1; rf->rof2 = rof2; /* Generate the pulse shape if rf->pulseName is appropriate */ genRf(rf); /* If the pulse shape has not been generated proceed as for init_rf */ switch (rf->type) { case RF_NULL: rf->rfDuration = shapelistpw(rfName,pw); /* Round to 200ns resolution*/ readRfPulse(rf); /* Set actual bandwidth according to pulse duration */ if ((FP_LT(rf->flip,FLIPLIMIT_LOW)) || (FP_GT(rf->flip,FLIPLIMIT_HIGH))) /* use excitation bandwidth */ rf->bandwidth = rf->header.bandwidth/rf->rfDuration; else /* use inversion bandwidth */ rf->bandwidth = rf->header.inversionBw/rf->rfDuration; break; default: /* Even though shape is properly quantized for some reason we need to use shapelistpw to round to 200ns resolution, otherwise duration may be significantly wrong ?? */ rf->rfDuration = shapelistpw(rf->pulseName,pw); break; } switch (rf->error) { case ERR_RF_SHAPE_MISSING: sgl_abort_message("ERROR: Can not find RF shape '%s.RF'",rfName); break; case ERR_RF_HEADER_ENTRIES: sgl_abort_message("ERROR rf shape '%s': incorrect header information",rfName); break; default: break; } if ((rf->header.rfFraction < 0) || (rf->header.rfFraction > 1)) sgl_abort_message("ERROR rf shape '%s': RF Fraction must be between 0 and 1",rfName); }
int lw_segment_envelope_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2) { double minq=FP_MIN(q1->x,q2->x); double maxq=FP_MAX(q1->x,q2->x); double minp=FP_MIN(p1->x,p2->x); double maxp=FP_MAX(p1->x,p2->x); if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) return LW_FALSE; minq=FP_MIN(q1->y,q2->y); maxq=FP_MAX(q1->y,q2->y); minp=FP_MIN(p1->y,p2->y); maxp=FP_MAX(p1->y,p2->y); if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) return LW_FALSE; return LW_TRUE; }
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 freqEx[MAXNSLICE]; double maxgradtime,spoilMoment,perTime,tau1,te_delay,tr_delay; double te2=0.0,te3=0.0,te2min,te3min,tau2,tau3,te2_delay,te3_delay=0; char minte2[MAXSTR],minte3[MAXSTR],spoilflag[MAXSTR]; int sepSliceRephase,sepReadRephase=0,readrev,table,shapeEx; 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 vper_mult = v7; // PE rewinder multiplier; turn off rewinder when 0 int vssc = v8; // Compressed steady-states int vacquire = v9; // Argument for setacqvar, to skip steady state acquires int vrfspoil_ctr = v10; // RF spoil counter int vrfspoil = v11; // RF spoil multiplier int vtrimage = v12; // Counts down from nt, trimage delay when 0 int vne = v13; // Number of echoes int vne_ctr = v14; // Echo loop counter int vneindex = v15; // Echo index, odd or even int vnelast = v16; // Check for last echo int vtrigblock = v17; // Number of slices per trigger block /* Initialize paramaters **********************************/ init_mri(); getstr("spoilflag",spoilflag); te2=getval("te2"); te3=getval("te3"); getstr("minte2",minte2); getstr("minte3",minte3); readrev=(int)getval("readrev"); /* Check for external PE table ***************************/ table = 0; if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); table = 1; } /* Set Rcvr/Xmtr phase increments for RF Spoiling ********/ /* Ref: Zur, Y., Magn. Res. Med., 21, 251, (1991) *******/ if (rfspoil[0] == 'y') { rcvrstepsize(rfphase); obsstepsize(rfphase); } /* Initialize gradient structures *************************/ shape_rf(&p1_rf,"p1",p1pat,p1,flip1,rof1,rof2 ); // excitation pulse init_slice(&ss_grad,"ss",thk); // slice select gradient init_slice_refocus(&ssr_grad,"ssr"); // slice refocus gradient init_readout(&ro_grad,"ro",lro,np,sw); // readout gradient ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); // dephase gradient init_phase(&pe_grad,"pe",lpe,nv); // phase encode gradient init_dephase(&spoil_grad,"spoil"); // optimized spoiler init_dephase(&ref_grad,"ref"); // readout rephase /* RF Calculations ****************************************/ calc_rf(&p1_rf,"tpwr1","tpwr1f"); /* Gradient calculations **********************************/ calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice_refocus(&ssr_grad, &ss_grad,WRITE,"gssr"); calc_readout(&ro_grad, WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,NOWRITE,"gror"); calc_phase(&pe_grad, NOWRITE,"gpe","tpe"); calc_dephase(&ref_grad,WRITE,ro_grad.m0,"",""); 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 slice refocus? ******/ maxgradtime = MAX(ror_grad.duration,pe_grad.duration); if (spoilflag[0] == 'y') maxgradtime = MAX(maxgradtime,spoil_grad.duration); tau1 = ss_grad.rfCenterBack + ssr_grad.duration + maxgradtime + ro_grad.timeToEcho + GRADIENT_RES; /* Equalize refocus and PE gradient durations *********/ if ((te >= tau1) && (minte[0] != 'y')) { sepSliceRephase = 1; // Set flag for separate slice rephase calc_sim_gradient(&ror_grad,&pe_grad,&spoil_grad,tpemin,WRITE); } else { sepSliceRephase = 0; calc_sim_gradient(&ror_grad,&pe_grad,&ssr_grad,tpemin,WRITE); calc_sim_gradient(&ror_grad,&spoil_grad,&null_grad,tpemin,NOWRITE); } perTime = 0.0; if ((perewind[0] == 'y') || (spoilflag[0] == 'y')) perTime = spoil_grad.duration; if (spoilflag[0] == 'n') spoil_grad.amp = 0.0; /* 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') create_inversion_recovery(); /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.ssamp,0,freqEx,ns,seqcon[1]); shapeEx = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freqEx,ns,ss_grad.rfFraction,seqcon[1]); /* Check that all Gradient calculations are ok ************/ sgl_error_check(sglerror); /* Min TE ******************************************/ tau1 = ss_grad.rfCenterBack + pe_grad.duration + ro_grad.timeToEcho; tau1 += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event temin = tau1 + GRADIENT_RES; /* ensure that te_delay is at least GRADIENT_RES */ te = granularity(te,GRADIENT_RES); if (minte[0] == 'y') { te = temin; putvalue("te",te); } if (FP_LT(te,temin)) { abort_message("TE too short. Minimum TE= %.3fms\n",temin*1000); } te_delay = te - tau1; /* Min TE2 *****************************************/ tau2 = (readrev) ? 2*ro_grad.timeFromEcho : ro_grad.duration+ref_grad.duration; te2min = tau2 + GRADIENT_RES; te2 = granularity(te2,GRADIENT_RES); if (minte2[0] == 'y') { te2 = te2min; putvalue("te2",te2); } if (FP_LT(te2,te2min)) { abort_message("TE2 too short. Minimum TE2= %.3fms\n",te2min*1000); } if (readrev) te2_delay = te2 - tau2; else { tau2 = ro_grad.duration + 3*ror_grad.duration; if (te2 >= tau2) { sepReadRephase = 1; // Set flag for separate read rephase te2_delay = te2 - ro_grad.duration - 2*ror_grad.duration; } else { sepReadRephase = 0; if (te2 > te2min+GRADIENT_RES) { ref_grad.duration = granularity(te2-ro_grad.duration-2*GRADIENT_RES,GRADIENT_RES); ref_grad.calcFlag = AMPLITUDE_FROM_MOMENT_DURATION; calc_dephase(&ref_grad,WRITE,ro_grad.m0,"",""); } te2_delay = te2 - ro_grad.duration - ref_grad.duration; } } /* Min TE3 *****************************************/ if (readrev) { tau3 = 2*ro_grad.timeToEcho; te3min = tau3 + GRADIENT_RES; te3 = granularity(te3,GRADIENT_RES); if (minte3[0] == 'y') { te3 = te3min; putvalue("te3",te3); } if (FP_LT(te3,te3min)) { abort_message("TE3 too short. Minimum TE3= %.3fms\n",te3min*1000); } te3_delay = te3 - tau3; } /* Now set the TE array accordingly */ putCmd("TE = 0"); /* Re-initialize TE */ putCmd("TE[1] = %f",te*1000); if (readrev) { for (i=1;i<ne;i++) { if (i%2 == 0) putCmd("TE[%d] = TE[%d]+%f",i+1,i,te3*1000); else putCmd("TE[%d] = TE[%d]+%f",i+1,i,te2*1000); } } else { for (i=1;i<ne;i++) putCmd("TE[%d] = TE[%d]+%f",i+1,i,te2*1000); } /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Min TR ******************************************/ trmin = ss_grad.duration + te_delay + pe_grad.duration + ne*ro_grad.duration + perTime + 2*GRADIENT_RES; trmin += (sepSliceRephase) ? ssr_grad.duration : 0.0; // Add slice refocusing if separate event if (readrev) trmin += (ne/2)*te2_delay + ((ne-1)/2)*te3_delay; else trmin += (sepReadRephase) ? (ne-1)*(te2_delay+2*ror_grad.duration) : (ne-1)*(te2_delay+ref_grad.duration); /* Increase TR if any options are selected *********/ 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 = %.3fms\n",trmin*1000); } /* Calculate tr delay */ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&per_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); /* PULSE SEQUENCE ***************************************/ status(A); rotate(); triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); delay(GRADIENT_RES); initval(fabs(ssc),vssc); // Compressed steady-state counter if (seqcon[2]=='s') assign(zero,vssc); // Zero for standard peloop assign(zero,vrfspoil_ctr); // RF spoil phase counter assign(zero,vrfspoil); // RF spoil multiplier 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); } /* Set rcvr/xmtr phase for RF spoiling *******************/ if (rfspoil[0] == 'y') { incr(vrfspoil_ctr); // vrfspoil_ctr = 1 2 3 4 5 6 add(vrfspoil,vrfspoil_ctr,vrfspoil); // vrfspoil = 1 3 6 10 15 21 xmtrphase(vrfspoil); rcvrphase(vrfspoil); } /* 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); } /* PE rewinder follows PE table; zero if turned off ***/ if (perewind[0] == 'y') assign(vpe_mult,vper_mult); else assign(zero,vper_mult); /* 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); } /* TTL scope trigger **********************************/ sp1on(); delay(GRADIENT_RES); sp1off(); /* 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(shapeEx,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Phase encode, refocus, and dephase gradient ********/ if (sepSliceRephase) { // separate slice refocus gradient obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0,0,-ssr_grad.amp,WAIT); delay(te_delay); // delay between slab refocus and pe pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,0, -pe_grad.increment,vpe_mult,WAIT); } else { pe_shapedgradient(pe_grad.name,pe_grad.duration,-ror_grad.amp,0,-ssr_grad.amp, -pe_grad.increment,vpe_mult,WAIT); delay(te_delay); // delay after refocus/pe } F_initval(ne,vne); loop(vne,vne_ctr); if (readrev) { mod2(vne_ctr,vneindex); ifzero(vneindex); /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); delay(te2_delay); endif(vnelast); elsenz(vneindex); /* Shift DDR for pro *******************************/ roff = -poffset(pro,-ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,-ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); delay(te3_delay); endif(vnelast); endif(vneindex); } else { /* Shift DDR for pro *******************************/ roff = -poffset(pro,ro_grad.roamp); /* Readout gradient ********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.amp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquisition ***************************************/ startacq(alfa); acquire(np,1.0/sw); delay(ro_grad.atDelayBack); endacq(); sub(vne,vne_ctr,vnelast); sub(vnelast,one,vnelast); ifzero(vnelast); elsenz(vnelast); if (sepReadRephase) { obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT); delay(te2_delay); obl_shapedgradient(ror_grad.name,ror_grad.duration,-ror_grad.amp,0,0,WAIT); } else { obl_shapedgradient(ref_grad.name,ref_grad.duration,-ref_grad.amp,0,0,WAIT); delay(te2_delay); } endif(vnelast); } endloop(vne_ctr); /* Rewind / spoiler gradient **************************/ if ((perewind[0] == 'y') || (spoilflag[0] == 'y')) { pe_shapedgradient(pe_grad.name,pe_grad.duration,spoil_grad.amp,0,0,pe_grad.increment,vper_mult,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); }
/*--------------------------------------*/ void gaussRf(RF_PULSE_T *rf) { int i; double t; double a,b; /* Set gauss shape type */ rf->type = RF_GAUSS; /* Set shape name */ setshapeRf(rf); /* Get pulse parameters */ getparsRf(rf); /* Round pulse resolution & duration and set the number of pulse points */ roundparsRf(rf); /* Set default cutoff (% of maximum) */ if (rf->cutoff < 0.001) rf->cutoff = 1.0; /* Otherwise make sure cutoff is 0.1, 0.5, 1.0, 5.0 or 10.0 */ if (rf->cutoff < 0.25) rf->cutoff = 0.1; else if ((rf->cutoff >= 0.25) && (rf->cutoff < 0.75)) rf->cutoff = 0.5; else if ((rf->cutoff >= 0.75) && (rf->cutoff < 2.5)) rf->cutoff = 1.0; else if ((rf->cutoff >= 2.5) && (rf->cutoff < 7.5)) rf->cutoff = 5.0; else if (rf->cutoff >= 7.5) rf->cutoff = 10.0; /* Set excitation and inversion bandwidths */ if (rf->cutoff == 0.1) { rf->header.bandwidth = 3.308; rf->header.inversionBw = 1.863; } if (rf->cutoff == 0.5) { rf->header.bandwidth = 2.896; rf->header.inversionBw = 1.635; } if (rf->cutoff == 1.0) { rf->header.bandwidth = 2.705; rf->header.inversionBw = 1.528; } if (rf->cutoff == 5.0) { rf->header.bandwidth = 2.216; rf->header.inversionBw = 1.263; } if (rf->cutoff == 10.0) { rf->header.bandwidth = 1.997; rf->header.inversionBw = 1.1455; } /* Set modulation type */ strcpy(rf->header.modulation,"amplitude"); /* Set rf fraction */ rf->header.rfFraction = 0.5; /* Set pulse type */ strcpy(rf->header.type,"selective"); /* Set actual bandwidth of pulse */ if ((FP_LT(rf->flip,FLIPLIMIT_LOW)) || (FP_GT(rf->flip,FLIPLIMIT_HIGH))) /* use excitation bandwidth */ rf->bandwidth = rf->header.bandwidth/rf->rfDuration; else /* use inversion bandwidth */ rf->bandwidth = rf->header.inversionBw/rf->rfDuration; /* Set SPL version */ rf->header.version = SPLVERSION; /* Allocate memory for pulse shape */ if ((rf->amp=(double *)malloc(rf->pts*sizeof(double))) == NULL) nomem(); if ((rf->phase=(double *)malloc(rf->pts*sizeof(double))) == NULL) nomem(); /* Generate shape */ a = -log(rf->cutoff/100.0)*4.0/(rf->rfDuration*rf->rfDuration); b = -rf->rfDuration/2.0 + rf->res/2.0; for (i=0;i<rf->pts;i++) { t = b+rf->res*i; rf->amp[i]=exp(-a*t*t); rf->phase[i]=0.0; } /* Calculate area under pulse */ calcintRf(rf); /* Scale amplitude so max is 1023.0 */ scaleampRf(rf); /* Write the pulse to disk */ writeRf(rf); /* Write pulse parameters */ putparsRf(rf); /* Update pulseName with new shape name */ strcpy(rf->pulseName,rf->shapeName); /* Free memory */ free(rf->amp); free(rf->phase); }
/*----------------------------------*/ void sincRf(RF_PULSE_T *rf) { int i; double t; double a,b; /* Set sinc shape type */ rf->type = RF_SINC; /* Set shape name */ setshapeRf(rf); /* Get pulse parameters */ getparsRf(rf); /* Round pulse resolution & duration and set the number of pulse points */ roundparsRf(rf); /* Set default number of lobes */ if (rf->lobes == 0) rf->lobes = 5; /* Otherwise make sure lobes is odd and between 1 and 13 */ if (rf->lobes < 1) rf->lobes = 1; if (rf->lobes > 13) rf->lobes = 13; if (rf->lobes%2 == 0) rf->lobes++; /* Set excitation and inversion bandwidths */ switch (rf->lobes) { case 1: rf->header.bandwidth = 1.998; rf->header.inversionBw = 1.252; break; case 3: rf->header.bandwidth = 4.018; rf->header.inversionBw = 2.598; break; case 5: rf->header.bandwidth = 5.944; rf->header.inversionBw = 4.702; break; case 7: rf->header.bandwidth = 7.884; rf->header.inversionBw = 6.298; break; case 9: rf->header.bandwidth = 9.856; rf->header.inversionBw = 8.398; break; case 11: rf->header.bandwidth = 11.790; rf->header.inversionBw = 9.985; break; case 13: rf->header.bandwidth = 13.783; rf->header.inversionBw = 11.918; break; } /* Set modulation type */ strcpy(rf->header.modulation,"amplitude"); /* Set rf fraction */ rf->header.rfFraction = 0.5; /* Set pulse type */ strcpy(rf->header.type,"selective"); /* Set actual bandwidth of pulse */ if ((FP_LT(rf->flip,FLIPLIMIT_LOW)) || (FP_GT(rf->flip,FLIPLIMIT_HIGH))) /* use excitation bandwidth */ rf->bandwidth = rf->header.bandwidth/rf->rfDuration; else /* use inversion bandwidth */ rf->bandwidth = rf->header.inversionBw/rf->rfDuration; /* Set SPL version */ rf->header.version = SPLVERSION; /* Allocate memory for pulse shape */ if ((rf->amp=(double *)malloc(rf->pts*sizeof(double))) == NULL) nomem(); if ((rf->phase=(double *)malloc(rf->pts*sizeof(double))) == NULL) nomem(); /* Generate shape */ a = -rf->rfDuration/2.0 + rf->res/2.0; b = M_PI*(rf->lobes + 1)/(rf->rfDuration - rf->res); for (i=0;i<rf->pts;i++) { t = b*(a+rf->res*i); if (t == 0.0) rf->amp[i]=1.0; else rf->amp[i]=sin(t)/t; rf->phase[i]=0.0; } /* Calculate area under pulse */ calcintRf(rf); /* Scale amplitude so max is 1023.0 */ scaleampRf(rf); /* Pulse amplitudes can't be negative, so set opposite phase instead */ absampRf(rf); /* Write the pulse to disk */ writeRf(rf); /* Write pulse parameters */ putparsRf(rf); /* Update pulseName with new shape name */ strcpy(rf->pulseName,rf->shapeName); /* Free memory */ free(rf->amp); free(rf->phase); }
BOX3D * lwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3) { double x1, x2, y1, y2, z1, z2; double angle, radius, sweep; /* angles from center */ double a1, a2, a3; /* angles from center once a1 is rotated to zero */ double r2, r3; double xe = 0.0, ye = 0.0; POINT4D *center; int i; BOX3D *box; LWDEBUG(2, "lwcircle_compute_box3d called."); radius = lwcircle_center(p1, p2, p3, ¢er); if (radius < 0.0) { LWDEBUG(3, "lwcircle_compute_box3d: zero radius"); /* * We've got a straight line here. Look to the end points for extents. * It's worth noting that when lwcircle_center returns < 0, center hasn't been allocated. */ x1 = (FP_LT(p1->x, p3->x)) ? p1->x : p3->x; x2 = (FP_GT(p1->x, p3->x)) ? p1->x : p3->x; y1 = (FP_LT(p1->y, p3->y)) ? p1->y : p3->y; y2 = (FP_GT(p1->y, p3->y)) ? p1->y : p3->y; z1 = (FP_LT(p1->z, p2->z)) ? p1->z : p2->z; z1 = (FP_LT(z1, p3->z)) ? z1 : p3->z; z2 = (FP_GT(p1->z, p2->z)) ? p1->z : p2->z; z2 = (FP_GT(z2, p3->z)) ? z2 : p3->z; box = lwalloc(sizeof(BOX3D)); box->xmin = x1; box->xmax = x2; box->ymin = y1; box->ymax = y2; box->zmin = z1; box->zmax = z2; LWDEBUGF(3, "lwcircle_compute_box3d: extents %.16f %.16f %.16f, %.16f %.16f %.16f", x1, y1, z1, x2, y2, z2); return box; } /* top = center->y + radius; left = center->x - radius; LWDEBUGF(3, "lwcircle_compute_box3d: center (%.16f, %.16f)", center->x, center->y); */ x1 = MAXFLOAT; x2 = -1 * MAXFLOAT; y1 = MAXFLOAT; y2 = -1 * MAXFLOAT; a1 = atan2(p1->y - center->y, p1->x - center->x); a2 = atan2(p2->y - center->y, p2->x - center->x); a3 = atan2(p3->y - center->y, p3->x - center->x); /* Rotate a2 and a3 such that a1 = 0 */ r2 = a2 - a1; r3 = a3 - a1; LWDEBUGF(4, "a1 %.16f, a2 %.16f, a3 %.16f", a1, a2, a3); LWDEBUGF(4, "r2 %.16f, r3 %.16f", r2, r3); /* * There are six cases here I'm interested in * Clockwise: * 1. a1-a2 < 180 == r2 < 0 && (r3 > 0 || r3 < r2) * 2. a1-a2 > 180 == r2 > 0 && (r3 > 0 && r3 < r2) * 3. a1-a2 > 180 == r2 > 0 && (r3 > r2 || r3 < 0) * Counter-clockwise: * 4. a1-a2 < 180 == r2 > 0 && (r3 < 0 || r3 > r2) * 5. a1-a2 > 180 == r2 < 0 && (r3 < 0 && r3 > r2) * 6. a1-a2 > 180 == r2 < 0 && (r3 < r2 || r3 > 0) * 3 and 6 are invalid cases where a3 is the midpoint. * BBOX is fundamental, so these cannot error out and will instead * calculate the sweep using a3 as the middle point. */ /* clockwise 1 */ if (FP_LT(r2, 0) && (FP_GT(r3, 0) || FP_LT(r3, r2))) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* clockwise 2 */ else if (FP_GT(r2, 0) && FP_GT(r3, 0) && FP_LT(r3, r2)) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* counter-clockwise 4 */ else if (FP_GT(r2, 0) && (FP_LT(r3, 0) || FP_GT(r3, r2))) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* counter-clockwise 5 */ else if (FP_LT(r2, 0) && FP_LT(r3, 0) && FP_GT(r3, r2)) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* clockwise invalid 3 */ else if (FP_GT(r2, 0) && (FP_GT(r3, r2) || FP_LT(r3, 0))) { sweep = (FP_GT(r2, 0)) ? (r2 - 2 * M_PI) : r2; } /* clockwise invalid 6 */ else { sweep = (FP_LT(r2, 0)) ? (r2 + 2 * M_PI) : r2; } LWDEBUGF(3, "a1 %.16f, a2 %.16f, a3 %.16f, sweep %.16f", a1, a2, a3, sweep); angle = 0.0; for (i=0; i < 6; i++) { switch (i) { /* right extent */ case 0: angle = 0.0; xe = center->x + radius; ye = center->y; break; /* top extent */ case 1: angle = M_PI_2; xe = center->x; ye = center->y + radius; break; /* left extent */ case 2: angle = M_PI; xe = center->x - radius; ye = center->y; break; /* bottom extent */ case 3: angle = -1 * M_PI_2; xe = center->x; ye = center->y - radius; break; /* first point */ case 4: angle = a1; xe = p1->x; ye = p1->y; break; /* last point */ case 5: angle = a3; xe = p3->x; ye = p3->y; break; } /* determine if the extents are outside the arc */ if (i < 4) { if (FP_GT(sweep, 0.0)) { if (FP_LT(a3, a1)) { if (FP_GT(angle, (a3 + 2 * M_PI)) || FP_LT(angle, a1)) continue; } else { if (FP_GT(angle, a3) || FP_LT(angle, a1)) continue; } } else { if (FP_GT(a3, a1)) { if (FP_LT(angle, (a3 - 2 * M_PI)) || FP_GT(angle, a1)) continue; } else { if (FP_LT(angle, a3) || FP_GT(angle, a1)) continue; } } } LWDEBUGF(3, "lwcircle_compute_box3d: potential extreame %d (%.16f, %.16f)", i, xe, ye); x1 = (FP_LT(x1, xe)) ? x1 : xe; y1 = (FP_LT(y1, ye)) ? y1 : ye; x2 = (FP_GT(x2, xe)) ? x2 : xe; y2 = (FP_GT(y2, ye)) ? y2 : ye; } LWDEBUGF(3, "lwcircle_compute_box3d: extreames found (%.16f %.16f, %.16f %.16f)", x1, y1, x2, y2); /* x1 = center->x + x1 * radius; x2 = center->x + x2 * radius; y1 = center->y + y1 * radius; y2 = center->y + y2 * radius; */ z1 = (FP_LT(p1->z, p2->z)) ? p1->z : p2->z; z1 = (FP_LT(z1, p3->z)) ? z1 : p3->z; z2 = (FP_GT(p1->z, p2->z)) ? p1->z : p2->z; z2 = (FP_GT(z2, p3->z)) ? z2 : p3->z; box = lwalloc(sizeof(BOX3D)); box->xmin = x1; box->xmax = x2; box->ymin = y1; box->ymax = y2; box->zmin = z1; box->zmax = z2; lwfree(center); return box; }
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); }
static int lwcircle_calculate_gbox(POINT4D p1, POINT4D p2, POINT4D p3, GBOX *gbox) { double x1, x2, y1, y2, z1, z2, m1, m2; double angle, radius, sweep; /* angles from center */ double a1, a2, a3; /* angles from center once a1 is rotated to zero */ double r2, r3; double xe = 0.0, ye = 0.0; POINT4D *center; int i; LWDEBUG(2, "lwcircle_calculate_gbox called."); radius = lwcircle_center(&p1, &p2, &p3, ¢er); if (radius < 0.0) return G_FAILURE; x1 = MAXFLOAT; x2 = -1 * MAXFLOAT; y1 = MAXFLOAT; y2 = -1 * MAXFLOAT; a1 = atan2(p1.y - center->y, p1.x - center->x); a2 = atan2(p2.y - center->y, p2.x - center->x); a3 = atan2(p3.y - center->y, p3.x - center->x); /* Rotate a2 and a3 such that a1 = 0 */ r2 = a2 - a1; r3 = a3 - a1; /* * There are six cases here I'm interested in * Clockwise: * 1. a1-a2 < 180 == r2 < 0 && (r3 > 0 || r3 < r2) * 2. a1-a2 > 180 == r2 > 0 && (r3 > 0 && r3 < r2) * 3. a1-a2 > 180 == r2 > 0 && (r3 > r2 || r3 < 0) * Counter-clockwise: * 4. a1-a2 < 180 == r2 > 0 && (r3 < 0 || r3 > r2) * 5. a1-a2 > 180 == r2 < 0 && (r3 < 0 && r3 > r2) * 6. a1-a2 > 180 == r2 < 0 && (r3 < r2 || r3 > 0) * 3 and 6 are invalid cases where a3 is the midpoint. * BBOX is fundamental, so these cannot error out and will instead * calculate the sweep using a3 as the middle point. */ /* clockwise 1 */ if (FP_LT(r2, 0) && (FP_GT(r3, 0) || FP_LT(r3, r2))) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* clockwise 2 */ else if (FP_GT(r2, 0) && FP_GT(r3, 0) && FP_LT(r3, r2)) { sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3; } /* counter-clockwise 4 */ else if (FP_GT(r2, 0) && (FP_LT(r3, 0) || FP_GT(r3, r2))) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* counter-clockwise 5 */ else if (FP_LT(r2, 0) && FP_LT(r3, 0) && FP_GT(r3, r2)) { sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3; } /* clockwise invalid 3 */ else if (FP_GT(r2, 0) && (FP_GT(r3, r2) || FP_LT(r3, 0))) { sweep = (FP_GT(r2, 0)) ? (r2 - 2 * M_PI) : r2; } /* clockwise invalid 6 */ else { sweep = (FP_LT(r2, 0)) ? (r2 + 2 * M_PI) : r2; } LWDEBUGF(3, "a1 %.16f, a2 %.16f, a3 %.16f, sweep %.16f", a1, a2, a3, sweep); angle = 0.0; for (i=0; i < 6; i++) { switch (i) { /* right extent */ case 0: angle = 0.0; xe = center->x + radius; ye = center->y; break; /* top extent */ case 1: angle = M_PI_2; xe = center->x; ye = center->y + radius; break; /* left extent */ case 2: angle = M_PI; xe = center->x - radius; ye = center->y; break; /* bottom extent */ case 3: angle = -1 * M_PI_2; xe = center->x; ye = center->y - radius; break; /* first point */ case 4: angle = a1; xe = p1.x; ye = p1.y; break; /* last point */ case 5: angle = a3; xe = p3.x; ye = p3.y; break; } /* determine if the extents are outside the arc */ if (i < 4) { if (FP_GT(sweep, 0.0)) { if (FP_LT(a3, a1)) { if (FP_GT(angle, (a3 + 2 * M_PI)) || FP_LT(angle, a1)) continue; } else { if (FP_GT(angle, a3) || FP_LT(angle, a1)) continue; } } else { if (FP_GT(a3, a1)) { if (FP_LT(angle, (a3 - 2 * M_PI)) || FP_GT(angle, a1)) continue; } else { if (FP_LT(angle, a3) || FP_GT(angle, a1)) continue; } } } LWDEBUGF(3, "lwcircle_calculate_gbox: potential extreame %d (%.16f, %.16f)", i, xe, ye); x1 = (FP_LT(x1, xe)) ? x1 : xe; y1 = (FP_LT(y1, ye)) ? y1 : ye; x2 = (FP_GT(x2, xe)) ? x2 : xe; y2 = (FP_GT(y2, ye)) ? y2 : ye; } LWDEBUGF(3, "lwcircle_calculate_gbox: extreames found (%.16f %.16f, %.16f %.16f)", x1, y1, x2, y2); z1 = FP_MIN(p1.z, p2.z); z1 = FP_MIN(z1, p3.z); z2 = FP_MAX(p1.z, p2.z); z2 = FP_MAX(z2, p3.z); m1 = FP_MIN(p1.m, p2.m); m1 = FP_MIN(m1, p3.m); m2 = FP_MAX(p1.m, p2.m); m2 = FP_MAX(m2, p3.m); gbox->xmin = x1; gbox->xmax = x2; gbox->ymin = y1; gbox->ymax = y2; if ( FLAGS_GET_Z(gbox->flags) ) { gbox->zmin = z1; gbox->zmax = z2; } if ( FLAGS_GET_M(gbox->flags) ) { gbox->mmin = m1; gbox->mmax = m2; } return G_SUCCESS; }
void pulsesequence() { /* Internal variable declarations *********************/ int shapelist90,shapelist180,shapelistte=0; double kzero,thk2fact,thk3fact; double te1=0.0,te1_delay,te2_delay,te3_delay,tr_delay,te_delay1=0.0,te_delay2=0.0; double crushm0,pem0,gcrushr,gcrushp,gcrushs; double freq90[MAXNSLICE],freq180[MAXNSLICE],freqte[MAXNSLICE]; char autocrush[MAXSTR]; /* Phase encode variables */ FILE *fp; int tab[4096],petab[4096],odd,seg0,tabscheme; char tabname[MAXSTR],tabfile[MAXSTR]; int i,j,k; /* Diffusion variables */ double Gro,Gss; // "gdiff" for readout/readout refocus and slice/slice refocus double dgro,Dgro; // delta and DELTA for readout dephase & readout double dgss,Dgss; // delta and DELTA for excitation ss double dgss3,Dgss3; // delta and DELTA for spin echo prep ss double dcrush3,Dcrush3; // delta and DELTA for spin echo prep crusher double dgss2,Dgss2; // delta and DELTA for refocus ss double dcrush2,Dcrush2; // delta and DELTA for refocus crusher /* 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 vpe2_steps = v10; // Number of PE2 steps int vpe2_ctr = v11; // PE2 loop counter int vpe2_mult = v12; // PE2 multiplier int vpe2_offset = v13; // PE2/2 for non-table offset int vssc = v14; // Compressed steady-states int vtrimage = v15; // Counts down from nt, trimage delay when 0 int vacquire = v16; // Argument for setacqvar, to skip steady state acquires int vphase180 = v17; // phase of 180 degree refocusing pulse int vtrigblock = v18; // Number of slices per trigger block /* Initialize paramaters ******************************/ init_mri(); kzero = getval("kzero"); getstr("autocrush",autocrush); tabscheme = getval("tabscheme"); getstr("spoilflag",spoilflag); /* Allow ROxPE2 projection ****************************/ if (profile[0] == 'y' && profile[1] == 'n') { etl=1; kzero=1; nv=nv2; } else { /* Check kzero is valid *****************************/ if (kzero<1) kzero=1; if (kzero>etl) kzero=etl; putCmd("kzero = %d",(int)kzero); } /* Set petable name and full path *********************/ sprintf(tabname,"fse%d_%d_%d",(int)nv,(int)etl,(int)kzero); putCmd("petable = '%s'",tabname); strcpy(tabfile,userdir); strcat(tabfile,"/tablib/"); strcat(tabfile,tabname); /* Generate phase encode table ************************/ if (tabscheme) { /* New scheme */ /* Calculate PE table for kzero=1 */ seg0=nseg/2; for (j=0;j<seg0;j++) { for (i=0;i<etl/2;i++) tab[j*(int)etl+i] = i*nseg+seg0-j; for (i=1;i<=etl/2;i++) tab[(j+1)*(int)etl-i] = tab[j*(int)etl]-i*nseg; } for (j=seg0;j<nseg;j++) { for (i=0;i<=etl/2;i++) tab[j*(int)etl+i] = i*nseg+seg0-j; for (i=1;i<etl/2;i++) tab[(j+1)*(int)etl-i] = tab[j*(int)etl]-i*nseg; } /* Adjust for kzero */ for (i=0;i<nseg;i++) { k=i*etl; for (j=0;j<kzero-1;j++) petab[k+j]=tab[k+(int)etl-(int)kzero+j+1]; for (j=kzero-1;j<etl;j++) petab[k+j]=tab[k+j-(int)kzero+1]; } } else { /* Original scheme */ /* Calculate PE table for kzero=1 */ odd=(int)nseg%2; seg0=nseg/2+odd; k=0; for (i=0;i<etl;i++) for (j=seg0-odd*i%2-1;j>=0;j--) tab[j*(int)etl+i] = k--; k=1; for (i=0;i<etl;i++) for (j=seg0-odd*i%2;j<nseg;j++) tab[j*(int)etl+i] = k++; /* Adjust for kzero */ for (i=0;i<nseg;i++) { k=i*etl; for (j=0;j<kzero-1;j++) petab[k+j]=tab[k+(int)etl-j-1]; for (j=kzero-1;j<etl;j++) petab[k+j]=tab[k+j-(int)kzero+1]; } } /* Set petable name and full path *********************/ sprintf(tabname,"fse%d_%d_%d",(int)nv,(int)etl,(int)kzero); putCmd("petable = '%s'",tabname); strcpy(tabfile,userdir); strcat(tabfile,"/tablib/"); strcat(tabfile,tabname); /* Write to tabfile ***********************************/ fp=fopen(tabfile,"w"); fprintf(fp,"t1 ="); for (i=0;i<nseg;i++) { fprintf(fp,"\n"); for (j=0;j<etl;j++) fprintf(fp,"%3d\t",petab[i*(int)etl+j]); } fclose(fp); /* Set pelist to contain table order ******************/ putCmd("pelist = 0"); /* Re-initialize pelist */ for (i=0;i<nseg*etl;i++) putCmd("pelist[%d] = %d",i+1,petab[i]); /* Avoid gradient slew rate errors */ for (i=0;i<nseg*etl;i++) if (abs(petab[i]) > nv/2) petab[i]=0; /* Set phase encode table *****************************/ settable(t1,(int)etl*nseg,petab); /* 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"); /* Calculate thk2fact to ensure gss=gss2 for the choice of p1 and p2 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk2fact=p2_rf.bandwidth/p1_rf.bandwidth; putvalue("thk2fact",thk2fact); /* Initialize gradient structures *********************/ init_readout(&ro_grad,"ro",lro,np,sw); ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_phase(&pe2_grad,"pe2",lpe2,nv2); init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_slice_refocus(&ssr_grad,"ssr"); init_dephase(&crush_grad,"crush"); /* Gradient calculations ******************************/ calc_readout(&ro_grad,WRITE,"gro","sw","at"); calc_readout_refocus(&ror_grad,&ro_grad,WRITE,"gror"); calc_phase(&pe_grad,NOWRITE,"",""); calc_phase(&pe2_grad,NOWRITE,"",""); calc_slice(&ss_grad,&p1_rf,WRITE,"gss"); calc_slice(&ss2_grad,&p2_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,WRITE,"gssr"); /* Equalize refocus gradient durations ****************/ calc_sim_gradient(&ror_grad,&null_grad,&ssr_grad,0.0,WRITE); /* Equalize PE gradient durations *********************/ calc_sim_gradient(&pe_grad,&pe2_grad,&null_grad,0.0,WRITE); /* Set crushing gradient moment ***********************/ crushm0=fabs(gcrush*tcrush); if (spoilflag[0] == 'y') { init_generic(&spoil_grad,"spoil",gspoil,tspoil); calc_generic(&spoil_grad,WRITE,"gspoil","tspoil"); } /* 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') create_inversion_recovery(); if (diff[0] == 'y') init_diffusion(&diffusion,&diff_grad,"diff",gdiff,tdelta); if (diff[0] == 'y') { /* Diffusion encoding is during spin echo preparation */ spinecho[0]='y'; putCmd("spinecho='y'"); } if (spinecho[0] == 'y') { /* spin echo preparation */ shape_rf(&p3_rf,"p3",p3pat,p3,flip3,rof1,rof2); calc_rf(&p3_rf,"tpwr3","tpwr3f"); /* Calculate thk3fact to ensure gss=gss2=gss3 for the choice of p1, p2 and p3 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk3fact=p3_rf.bandwidth/p1_rf.bandwidth; putvalue("thk3fact",thk3fact); init_slice(&ss3_grad,"ss3",thk*thk3fact); calc_slice(&ss3_grad,&p3_rf,WRITE,""); putvalue("gss3",ss3_grad.ssamp); offsetlist(pss,ss3_grad.ssamp,0,freqte,ns,seqcon[1]); shapelistte = shapelist(p3_rf.pulseName,ss3_grad.rfDuration,freqte,ns,ss3_grad.rfFraction,seqcon[1]); /* Automatically set crushers to avoid unwanted echoes */ if (autocrush[0] == 'y') { if (crushm0 < 0.6*ro_grad.m0) crushm0=0.6*ro_grad.m0; } } /* Make sure crushing in PE dimensions does not refocus signal from 180 */ pem0 = (pe_grad.m0 > pe2_grad.m0) ? pe_grad.m0 : pe2_grad.m0; calc_dephase(&crush_grad,WRITE,crushm0+pem0,"",""); gcrushr = crush_grad.amp*crushm0/crush_grad.m0; gcrushp = crush_grad.amp*(crushm0+pe_grad.m0)/crush_grad.m0; gcrushs = crush_grad.amp*(crushm0+pe2_grad.m0)/crush_grad.m0; sgl_error_check(sglerror); /* Set up frequency offset pulse shape list ***********/ offsetlist(pss,ss_grad.amp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shapelist90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shapelist180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* To ensure proper overlap spin and stimulated echoes ensure that the middle of the refocusing RF pulse is the centre of the pulse and that echoes are formed in the centre of the acquisition window */ if (ss2_grad.rfFraction != 0.5) abort_message( "ERROR %s: Refocusing RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss2_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 ****/ esp = granularity(esp,2*GRADIENT_RES); tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + GRADIENT_RES; tau2 = ss2_grad.rfCenterBack + crush_grad.duration + pe_grad.duration + ro_grad.timeToEcho + GRADIENT_RES; tau3 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront + GRADIENT_RES; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing if (minesp[0] == 'y') { esp = espmin; putvalue("esp",esp); } if (FP_LT(esp,espmin)) { abort_message("ERROR %s: Echo spacing too small, minimum is %.3fms\n",seqfil,espmin*1000); } te1_delay = esp/2.0 - tau1 + GRADIENT_RES; // Intra-esp delays te2_delay = esp/2.0 - tau2 + GRADIENT_RES; te3_delay = esp/2.0 - tau3 + GRADIENT_RES; /* Spin echo preparation ******************************/ if (spinecho[0] == 'y') { te = granularity(te,2*GRADIENT_RES); te1 = te-kzero*esp; tau1 = ss_grad.rfCenterBack + ssr_grad.duration + crush_grad.duration + ss3_grad.duration/2.0 + GRADIENT_RES; tau2 = ss3_grad.duration/2.0 + crush_grad.duration + GRADIENT_RES; 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 = ss3_grad.duration + 2*crush_grad.duration; /* set minimum diffusion structure requirements for gradient echo: taudiff, tDELTA, te and minte[0] */ set_diffusion(&diffusion,taudiff,tDELTA,te1,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') { te1 = temin; te = te1+kzero*esp; putvalue("te",te); } te_delay1 = te1/2 - tau1 + GRADIENT_RES; te_delay2 = te1/2 - tau2 + GRADIENT_RES; if (FP_LT(te,temin+kzero*esp)) { abort_message("ERROR %s: TE too short, minimum TE = %.3f ms\n",seqfil,temin*1000); } } else putvalue("te",kzero*esp); // Return effective TE /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* 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); // readout dephase & readout delta Gro = ro_grad.m0ref/dgro; // readout dephase & readout gradient strength Dgro = dgro+2*crush_grad.duration+ss2_grad.duration+te2_delay+pe_grad.duration; // readout dephase & readout DELTA dgss = 0.5*(ss_grad.rfCenterBack+ssr_grad.duration); // slice & slice refocus delta Gss = ss_grad.m0ref/dgss; // slice & slice refocus gradient strength Dgss = dgss; // slice & slice refocus DELTA dgss2 = (ss2_grad.duration-ss2_grad.tramp)/2.0; // refocus slice select delta Dgss2 = dgss2; // refocus slice select DELTA dcrush2 = crush_grad.duration-crush_grad.tramp; // refocus crusher delta Dcrush2 = crush_grad.duration+ss2_grad.duration; // refocus crusher DELTA dcrush3 = crush_grad.duration-crush_grad.tramp; // spin echo prep crusher delta Dcrush3 = crush_grad.duration+ss3_grad.duration; // spin echo prep crusher DELTA dgss3 = (ss3_grad.duration-ss3_grad.tramp)/2.0; // spin echo prep slice select delta Dgss3 = dgss3; // spin echo prep slice select DELTA 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(gcrushr,dcrush2,Dcrush2); diffusion.bro[i] += bval_nested(Gro,dgro,Dgro,gcrushr,dcrush2,Dcrush2); /* Phase */ diffusion.bpe[i] += bval(gcrushp,dcrush2,Dcrush2); /* Slice */ diffusion.bsl[i] += bval(Gss,dgss,Dgss); diffusion.bsl[i] += bval(gcrushs,dcrush2,Dcrush2); diffusion.bsl[i] += bval(ss2_grad.ssamp,dgss2,Dgss2); diffusion.bsl[i] += bval_nested(gcrushs,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval2(gcrushr,gcrushp,dcrush2,Dcrush2); /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,gcrushs,dcrush2,Dcrush2); diffusion.brs[i] += bval_cross(Gro,dgro,Dgro,ss2_grad.ssamp,dgss2,Dgss2); diffusion.brs[i] += bval2(gcrushr,gcrushs,dcrush2,Dcrush2); diffusion.brs[i] += bval_cross(gcrushr,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval2(gcrushs,gcrushp,dcrush2,Dcrush2); diffusion.bsp[i] += bval_cross(gcrushp,dcrush2,Dcrush2,ss2_grad.ssamp,dgss2,Dgss2); if (spinecho[0] == 'y') { /* Readout */ diffusion.bro[i] += bval(crush_grad.amp,dcrush3,Dcrush3); diffusion.bro[i] += bval_nested(gdiff*droval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); /* Slice */ diffusion.bsl[i] += bval(ss3_grad.amp,dgss3,Dgss3); diffusion.bsl[i] += bval_nested(gdiff*dslval,tdelta,tDELTA,ss3_grad.ssamp,dgss3,Dgss3); /* Readout/Slice Cross-terms */ diffusion.brs[i] += bval_cross(gdiff*dslval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); diffusion.brs[i] += bval_cross(gdiff*droval,tdelta,tDELTA,ss3_grad.amp,dgss3,Dgss3); diffusion.brs[i] += bval_cross(crush_grad.amp,dcrush3,Dcrush3,ss3_grad.amp,dgss3,Dgss3); /* Readout/Phase Cross-terms */ diffusion.brp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,crush_grad.amp,dcrush3,Dcrush3); /* Slice/Phase Cross-terms */ diffusion.bsp[i] += bval_cross(gdiff*dpeval,tdelta,tDELTA,ss3_grad.amp,dgss3,Dgss3); } } /* End for-all-directions */ /* Write the values */ write_bvalues(&diffusion,"bval","bvalue","max_bval"); } /* Minimum TR *****************************************/ trmin = ss_grad.rfCenterFront + etl*esp + ro_grad.timeFromEcho + pe_grad.duration + te3_delay + 2*GRADIENT_RES; if (spoilflag[0] == 'y') trmin += spoil_grad.duration; /* Increase TR if any options are selected ************/ if (sat[0] == 'y') trmin += satTime; if (fsat[0] == 'y') trmin += fsatTime; if (mt[0] == 'y') trmin += mtTime; if (spinecho[0] == 'y') trmin += te1; 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("ERROR %s: TR too short, minimum TR = %.3fms\n",seqfil,trmin*1000); } /* Calculate tr delay *********************************/ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set number of segments for profile or full image ***/ nseg = prep_profile(profile[0],nseg,&pe_grad,&null_grad); pe2_steps = prep_profile(profile[1],nv2,&pe2_grad,&null_grad); F_initval(pe2_steps/2.0,vpe2_offset); /* Shift DDR for pro **********************************/ roff = -poffset(pro,ro_grad.roamp); /* Adjust experiment time for VnmrJ *******************/ if (ssc<0) { if (seqcon[2] == 's' && seqcon[3]=='s') g_setExpTime(trmean*ntmean*arraydim - ssc*arraydim); else if (seqcon[2]=='s') g_setExpTime(trmean*nseg*(ntmean*pe2_steps*arraydim - ssc*arraydim)); else if (seqcon[3]=='s') g_setExpTime(trmean*pe2_steps*(ntmean*nseg*arraydim - ssc*arraydim)); else g_setExpTime(trmean*(ntmean*pe_steps*pe2_steps*arraydim - ssc*arraydim)); } else g_setExpTime(trmean*ntmean*nseg*pe2_steps*arraydim + tr*ssc); /* 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' && seqcon[3]=='s') assign(zero,vssc); // Zero for standard peloop and pe2loop 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); /* trigger */ if (ticks > 0) F_initval((double)nsblock,vtrigblock); /* Begin phase-encode loop ****************************/ peloop2(seqcon[3],pe2_steps,vpe2_steps,vpe2_ctr); /* Begin phase-encode loop ****************************/ peloop(seqcon[2],nseg,vseg,vseg_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); if (seqcon[2] == 'c') sub(vseg_ctr,vssc,vseg_ctr); // vseg_ctr counts up from -ssc else if (seqcon[3] == 'c') sub(vpe2_ctr,vssc,vpe2_ctr); // vpe2_ctr counts up from -ssc assign(zero,vssc); if (seqcon[2] == 's' && seqcon[3]=='s') assign(zero,vacquire); // Always acquire for non-compressed loop else { if (seqcon[2] == 'c') { ifzero(vseg_ctr); assign(zero,vacquire); // Start acquiring when vseg_ctr reaches zero endif(vseg_ctr); } else if (seqcon[3] == 'c') { ifzero(vpe2_ctr); assign(zero,vacquire); // Start acquiring when vpe2_ctr reaches zero endif(vpe2_ctr); } } setacqvar(vacquire); // Turn on acquire when vacquire is zero /* Use standard encoding order for 2nd PE dimension */ ifzero(vacquire); sub(vpe2_ctr,vpe2_offset,vpe2_mult); elsenz(vacquire); sub(zero,vpe2_offset,vpe2_mult); endif(vacquire); 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(); /* 90 degree 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(shapelist90,ss_grad.rfDuration,oph,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* Spin echo preparation ******************************/ if (spinecho[0] == 'y') { obl_shapedgradient(ssr_grad.name,ssr_grad.duration,0.0,0.0,-ssr_grad.amp,WAIT); if (diff[0] == 'y') { delay(diffusion.d1); diffusion_dephase(&diffusion,dro,dpe,dsl); delay(diffusion.d2); } else delay(te_delay1); obspower(p3_rf.powerCoarse); obspwrf(p3_rf.powerFine); obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0.0,0.0,WAIT); obl_shapedgradient(ss3_grad.name,ss3_grad.duration,0,0,ss3_grad.amp,NOWAIT); delay(ss3_grad.rfDelayFront); shapedpulselist(shapelistte,ss3_grad.rfDuration,vphase180,rof1,rof2,seqcon[1],vms_ctr); delay(ss3_grad.rfDelayBack); obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0.0,0.0,WAIT); if (diff[0] == 'y') { delay(diffusion.d3); diffusion_rephase(&diffusion,dro,dpe,dsl); delay(diffusion.d4); } else delay(te_delay2); delay(ss_grad.duration/2.0); delay(te1_delay); obspower(p2_rf.powerCoarse); obspwrf(p2_rf.powerFine); obl_shapedgradient(ror_grad.name,ror_grad.duration,ror_grad.amp,0.0,0.0,WAIT); } else { /* 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); } F_initval(etl,vetl); loop(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 *********************************/ obl_shapedgradient(crush_grad.name,crush_grad.duration,gcrushr,gcrushp,gcrushs,WAIT); 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); obl_shapedgradient(crush_grad.name,crush_grad.duration,gcrushr,gcrushp,gcrushs,WAIT); /* Second half-TE period ****************************/ delay(te2_delay); /* Phase-encode gradient ****************************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,-pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Readout gradient *********************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquire data *************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode gradient ******************/ pe2_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,pe_grad.increment,pe2_grad.increment,vpe_mult,vpe2_mult,WAIT); /* Second half-TE delay *****************************/ delay(te3_delay); endloop(vetl_ctr); if (spoilflag[0] == 'y') obl_shapedgradient(spoil_grad.name,spoil_grad.duration,spoil_grad.amp,spoil_grad.amp,spoil_grad.amp,WAIT); endmsloop(seqcon[1],vms_ctr); endpeloop(seqcon[2],vseg_ctr); endpeloop(seqcon[3],vpe2_ctr); /* Inter-image delay **********************************/ sub(ntrt,ct,vtrimage); decr(vtrimage); ifzero(vtrimage); delay(trimage); endif(vtrimage); }
/** ** @brief returns the kind of #CG_SEGMENT_INTERSECTION_TYPE behavior of lineseg 1 (constructed from p1 and p2) and lineseg 2 (constructed from q1 and q2) ** @param p1 start point of first straight linesegment ** @param p2 end point of first straight linesegment ** @param q1 start point of second line segment ** @param q2 end point of second line segment ** @return a #CG_SEGMENT_INTERSECTION_TYPE ** Returns one of ** SEG_ERROR = -1, ** SEG_NO_INTERSECTION = 0, ** SEG_COLINEAR = 1, ** SEG_CROSS_LEFT = 2, ** SEG_CROSS_RIGHT = 3, */ int lw_segment_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2) { double pq1, pq2, qp1, qp2; /* No envelope interaction => we are done. */ if (!lw_segment_envelope_intersects(p1, p2, q1, p2)) { return SEG_NO_INTERSECTION; } /* Are the start and end points of q on the same side of p? */ pq1=lw_segment_side(p1,p2,q1); pq2=lw_segment_side(p1,p2,q2); if ((pq1>0 && pq2>0) || (pq1<0 && pq2<0)) { return SEG_NO_INTERSECTION; } /* Are the start and end points of p on the same side of q? */ qp1=lw_segment_side(q1,q2,p1); qp2=lw_segment_side(q1,q2,p2); if ( (qp1 > 0.0 && qp2 > 0.0) || (qp1 < 0.0 && qp2 < 0.0) ) { return SEG_NO_INTERSECTION; } /* Nobody is on one side or another? Must be colinear. */ if ( pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0 ) { return SEG_COLINEAR; } /* ** When one end-point touches, the sidedness is determined by the ** location of the other end-point. Only touches by the first point ** will be considered "real" to avoid double counting. */ LWDEBUGF(4, "pq1=%.15g pq2=%.15g", pq1, pq2); LWDEBUGF(4, "qp1=%.15g qp2=%.15g", qp1, qp2); /* Second point of p or q touches, it's not a crossing. */ if ( pq2 == 0.0 || qp2 == 0.0 ) { return SEG_NO_INTERSECTION; } /* First point of p touches, it's a "crossing". */ if ( pq1 == 0.0 ) { if ( FP_GT(pq2,0.0) ) return SEG_CROSS_RIGHT; else return SEG_CROSS_LEFT; } /* First point of q touches, it's a crossing. */ if ( qp1 == 0.0 ) { if ( FP_LT(pq1,pq2) ) return SEG_CROSS_RIGHT; else return SEG_CROSS_LEFT; } /* The segments cross, what direction is the crossing? */ if ( FP_LT(pq1,pq2) ) return SEG_CROSS_RIGHT; else return SEG_CROSS_LEFT; /* This should never happen! */ return SEG_ERROR; }
pulsesequence() { /* Internal variable declarations *************************/ int shapelist90,shapelist180; int table = 0; double tau1,tau2,tau3,te1_delay,te2_delay,te3_delay,tr_delay; double freq90[MAXNSLICE],freq180[MAXNSLICE]; double thk2fact,crush_step,neby2,crush_ind; int suppressSTE,*crushtab; char crushmod[MAXSTR]; 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 vpe_mult = v3; // PE multiplier, ranges from -PE/2 to PE/2 int vpe_offset = v4; // PE/2 for non-table offset int vms_slices = v5; // Number of slices int vms_ctr = v6; // Slice loop counter int vne = v7; // Number of echoes int vne_ctr = v8; // Echo loop counter 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 vphase90 = v12; // Phase of 90 degree excitation pulse int vphase180 = v13; // Phase of 180 degree refocusing pulse int vphindex = v14; // Phase cycle index int vneindex = v15; // Echo index, odd or even int vcrush = v16; // Crusher modulation int vtrigblock = v17; // Number of slices per trigger block /* Initialize paramaters **********************************/ init_mri(); getstr("crushmod",crushmod); suppressSTE=getval("suppressSTE"); /* Load external PE table ********************************/ if (strcmp(petable,"n") && strcmp(petable,"N") && strcmp(petable,"")) { loadtable(petable); 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"); /* Calculate thk2fact to ensure gss=gss2 for the choice of p1 and p2 so that the sequence remains robust in the absence of correct balancing of slice select and slice refocus gradients */ thk2fact=p2_rf.bandwidth/p1_rf.bandwidth; putvalue("thk2fact",thk2fact); /* Initialize gradient structures *************************/ init_readout(&ro_grad,"ro",lro,np,sw); ro_grad.pad1=alfa; ro_grad.pad2=alfa; init_readout_refocus(&ror_grad,"ror"); init_phase(&pe_grad,"pe",lpe,nv); init_slice(&ss_grad,"ss",thk); init_slice(&ss2_grad,"ss2",thk*thk2fact); init_slice_refocus(&ssr_grad,"ssr"); init_generic(&crush_grad,"crush",gcrush,tcrush); /* 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,&p2_rf,WRITE,""); calc_slice_refocus(&ssr_grad,&ss_grad,NOWRITE,"gssr"); calc_generic(&crush_grad,WRITE,"",""); /* Equalize slice 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') create_inversion_recovery(); sgl_error_check(sglerror); /* Set up frequency offset pulse shape list ********/ offsetlist(pss,ss_grad.amp,0,freq90,ns,seqcon[1]); offsetlist(pss,ss2_grad.ssamp,0,freq180,ns,seqcon[1]); shapelist90 = shapelist(p1_rf.pulseName,ss_grad.rfDuration,freq90,ns,ss_grad.rfFraction,seqcon[1]); shapelist180 = shapelist(p2_rf.pulseName,ss2_grad.rfDuration,freq180,ns,ss2_grad.rfFraction,seqcon[1]); /* To ensure proper overlap spin and stimulated echoes ensure that the middle of the refocusing RF pulse is the centre of the pulse and that echoes are formed in the centre of the acquisition window */ if (ss2_grad.rfFraction != 0.5) abort_message("ERROR %s: Refocusing RF pulse must be symmetric (RF fraction = %.2f)", seqfil,ss2_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 + crush_grad.duration + ss2_grad.rfCenterFront; tau2 = ss2_grad.rfCenterBack + pe_grad.duration + crush_grad.duration + ro_grad.timeToEcho; tau3 = ro_grad.timeFromEcho + pe_grad.duration + crush_grad.duration + ss2_grad.rfCenterFront; espmin = 2*MAX(MAX(tau1,tau2),tau3); // Minimum echo spacing espmin += 2*GRADIENT_RES; // Ensure that each delay is at least GRADIENT_RES te = granularity(te,2*GRADIENT_RES); if (minesp[0] == 'y') { te = espmin; putvalue("te",te); } if (FP_LT(te,espmin)) { abort_message("ERROR %s: Echo time too small, minimum is %.3fms\n",seqfil,espmin*1000); } te1_delay = te/2.0 - tau1; // Intra-esp delays te2_delay = te/2.0 - tau2; te3_delay = te/2.0 - tau3; /* Now set the TE processing array accordingly */ putCmd("TE = 0"); /* Re-initialize TE */ for (i=0;i<ne;i++) putCmd("TE[%d] = %f",i+1,te*1000*(i+1)); /* Check nsblock, the number of slices blocked together (used for triggering and/or inversion recovery) */ check_nsblock(); /* Minimum TR **************************************/ trmin = ss_grad.rfCenterFront + ne*te + ro_grad.timeFromEcho + pe_grad.duration + te3_delay + 2*GRADIENT_RES; /* Increase TR if any options are selected *********/ 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("ERROR %s: TR too short, minimum TR is %.3fms\n",seqfil,trmin*1000); } /* Calculate tr delay */ tr_delay = granularity((tr-trmin)/ns,GRADIENT_RES); /* Set pe_steps for profile or full image **********/ pe_steps = prep_profile(profile[0],nv,&pe_grad,&per_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); /* Set phase cycle tables */ if (suppressSTE) { if ((int)nt%2 == 1) abort_message("STE suppression requires a 2 step phase cycle. Set nt as a multiple of 2\n"); settable(t2,4,phref1s); settable(t3,4,phref2s); settable(t4,4,phrec1s); settable(t5,4,phrec2s); } else { settable(t2,4,phref1); settable(t3,4,phref2); settable(t4,4,phrec1); settable(t5,4,phrec2); } /* Set crusher table */ crushtab=malloc((int)ne*sizeof(int)); neby2=ceil(ne/2.0 - US); // US to handle precision errors crush_step=gcrush/neby2; for (i=0; i<ne; i++) { crush_ind = (1.0-2.0*(i%2))*(neby2-floor(i/2)); crushtab[i] = (int)(crush_ind); } settable(t6,(int)ne,crushtab); /* PULSE SEQUENCE ***************************************/ status(A); rotate(); triggerSelect(trigger); // Select trigger input 1/2/3 obsoffset(resto); delay(GRADIENT_RES); 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 /* Phase for excitation pulse */ assign(zero,vphase90); /* 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); } 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(); /* 90 degree 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(shapelist90,ss_grad.rfDuration,vphase90,rof1,rof2,seqcon[1],vms_ctr); delay(ss_grad.rfDelayBack); /* 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); F_initval(ne,vne); loop(vne,vne_ctr); /* Phase cycle for refocusing pulse and receiver */ mod4(ct,vphindex); mod2(vne_ctr,vneindex); ifzero(vneindex); getelem(t2,vphindex,vphase180); getelem(t4,vphindex,oph); elsenz(vneindex); getelem(t3,vphindex,vphase180); getelem(t5,vphindex,oph); endif(vneindex); /* Crusher gradient modulation */ assign(one,vcrush); if (crushmod[0] == 'y') { assign(zero,vcrush); ifzero(vneindex); add(vcrush,one,vcrush); elsenz(vneindex); sub(vcrush,one,vcrush); endif(vneindex); } if (crushmod[0] == 'p') { getelem(t6,vne_ctr,vcrush); crush_grad.amp=crush_step; } /* 180 degree pulse *******************************/ if (crushmod[0] == 'y' || crushmod[0] == 'p') var3_shapedgradient(crush_grad.name,crush_grad.duration,0.0,0.0,0.0,0.0,0.0,crush_grad.amp,zero,zero,vcrush,WAIT); else obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0,crush_grad.amp,WAIT); 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); if (crushmod[0] == 'y' || crushmod[0] == 'p') var3_shapedgradient(crush_grad.name,crush_grad.duration,0.0,0.0,0.0,0.0,0.0,crush_grad.amp,zero,zero,vcrush,WAIT); else obl_shapedgradient(crush_grad.name,crush_grad.duration,crush_grad.amp,0,crush_grad.amp,WAIT); /* Second half-TE period ******************************/ delay(te2_delay); /* Phase-encode gradient ******************************/ pe_shapedgradient(pe_grad.name,pe_grad.duration,0,0,0,-pe_grad.increment,vpe_mult,WAIT); /* Readout gradient ************************************/ obl_shapedgradient(ro_grad.name,ro_grad.duration,ro_grad.roamp,0,0,NOWAIT); delay(ro_grad.atDelayFront-alfa); /* Acquire data ****************************************/ startacq(alfa); acquire(np,1.0/sw); endacq(); delay(ro_grad.atDelayBack); /* Rewinding phase-encode 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); endloop(vne_ctr); 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); }
static double circ_tree_distance_tree_internal(const CIRC_NODE* n1, const CIRC_NODE* n2, double threshold, double* min_dist, double* max_dist, GEOGRAPHIC_POINT* closest1, GEOGRAPHIC_POINT* closest2) { double max; double d, d_min; int i; LWDEBUGF(4, "entered, min_dist %.8g max_dist %.8g", *min_dist, *max_dist); // circ_tree_print(n1, 0); // circ_tree_print(n2, 0); /* Short circuit if we've already hit the minimum */ if( FP_LT(*min_dist, threshold) ) return *min_dist; /* If your minimum is greater than anyone's maximum, you can't hold the winner */ if( circ_node_min_distance(n1, n2) > *max_dist ) { LWDEBUGF(4, "pruning pair %p, %p", n1, n2); return MAXFLOAT; } /* If your maximum is a new low, we'll use that as our new global tolerance */ max = circ_node_max_distance(n1, n2); LWDEBUGF(5, "max %.8g", max); if( max < *max_dist ) *max_dist = max; /* Both leaf nodes, do a real distance calculation */ if( circ_node_is_leaf(n1) ) { if( circ_node_is_leaf(n2) ) { double d; GEOGRAPHIC_POINT close1, close2; LWDEBUGF(4, "testing leaf pair [%d], [%d]", n1->edge_num, n2->edge_num); /* One of the nodes is a point */ if ( n1->p1 == n1->p2 || n2->p1 == n2->p2 ) { GEOGRAPHIC_EDGE e; GEOGRAPHIC_POINT gp1, gp2; /* Both nodes are points! */ if ( n1->p1 == n1->p2 && n2->p1 == n2->p2 ) { geographic_point_init(n1->p1->x, n1->p1->y, &gp1); geographic_point_init(n2->p1->x, n2->p1->y, &gp2); close1 = gp1; close2 = gp2; d = sphere_distance(&gp1, &gp2); } /* Node 1 is a point */ else if ( n1->p1 == n1->p2 ) { geographic_point_init(n1->p1->x, n1->p1->y, &gp1); geographic_point_init(n2->p1->x, n2->p1->y, &(e.start)); geographic_point_init(n2->p2->x, n2->p2->y, &(e.end)); close1 = gp1; d = edge_distance_to_point(&e, &gp1, &close2); } /* Node 2 is a point */ else { geographic_point_init(n2->p1->x, n2->p1->y, &gp1); geographic_point_init(n1->p1->x, n1->p1->y, &(e.start)); geographic_point_init(n1->p2->x, n1->p2->y, &(e.end)); close1 = gp1; d = edge_distance_to_point(&e, &gp1, &close2); } LWDEBUGF(4, " got distance %g", d); } /* Both nodes are edges */ else { GEOGRAPHIC_EDGE e1, e2; GEOGRAPHIC_POINT g; POINT3D A1, A2, B1, B2; geographic_point_init(n1->p1->x, n1->p1->y, &(e1.start)); geographic_point_init(n1->p2->x, n1->p2->y, &(e1.end)); geographic_point_init(n2->p1->x, n2->p1->y, &(e2.start)); geographic_point_init(n2->p2->x, n2->p2->y, &(e2.end)); geog2cart(&(e1.start), &A1); geog2cart(&(e1.end), &A2); geog2cart(&(e2.start), &B1); geog2cart(&(e2.end), &B2); if ( edge_intersects(&A1, &A2, &B1, &B2) ) { d = 0.0; edge_intersection(&e1, &e2, &g); close1 = close2 = g; } else { d = edge_distance_to_edge(&e1, &e2, &close1, &close2); } LWDEBUGF(4, "edge_distance_to_edge returned %g", d); } if ( d < *min_dist ) { *min_dist = d; *closest1 = close1; *closest2 = close2; } return d; } else { d_min = MAXFLOAT; for ( i = 0; i < n2->num_nodes; i++ ) { d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2); d_min = FP_MIN(d_min, d); } return d_min; } } else { d_min = MAXFLOAT; for ( i = 0; i < n1->num_nodes; i++ ) { d = circ_tree_distance_tree_internal(n2, n1->nodes[i], threshold, min_dist, max_dist, closest1, closest2); d_min = FP_MIN(d_min, d); } return d_min; } }