
// include the headers of all sequence classes
#include <odinseq/seqall.h>


// The whole EPI sequence (including reco) is a C++ class
class METHOD_CLASS : public SeqMethod {

private:

  LDRint   NumOfEchoes;
  LDRbool  SEAcquisition;
  LDRint   Blades;
  LDRint   Shots;
  LDRfloat PulseDur;
  LDRbool  RampSampling;
  LDRbool  FatSaturation;
  LDRbool  fMRITrigger;
  LDRfloat FWbVal;
  LDRbool  FieldMap;

  LDRdoubleArr TEs;

  // sequence objects which are the elementary objects
  // to build the EPI sequence
  SeqPulsar  exc;
  SeqPulsar  refoc;
  SeqSat     fatsat;

  SeqAcqEPI  ge_epi;
  SeqAcqEPI  ge_epi_template;
  SeqAcqEPI  ge_epi_grappa;

  SeqAcqEPI  se_epi;
  SeqAcqEPI  se_epi_template;
  SeqAcqEPI  se_epi_grappa;

  SeqAcqDeph ge_deph;
  SeqAcqDeph se_deph;
  SeqAcqDeph deph_template; // one for both GE and SE
  SeqAcqDeph ge_deph_grappa;
  SeqAcqDeph se_deph_grappa;

  SeqAcqDeph ge_reph;
  SeqAcqDeph se_reph;
  SeqAcqDeph reph_template; // one for both GE and SE
  SeqAcqDeph ge_reph_grappa;
  SeqAcqDeph se_reph_grappa;

  SeqDelay   sedelay;

  SeqGradTrapezParallel rewind;
  SeqGradTrapezParallel rewind_template;
  SeqDelay rewind_paddelay;

  SeqVecIter phaseiter;

  SeqObjLoop sliceloop;
  SeqObjLoop reploop;
  SeqObjLoop segloop;
  SeqObjLoop grappaloop;
  SeqObjLoop echoloop;
  SeqObjLoop dummyloop;

  SeqDelay   trdelay;

  SeqObjVector gerewindvec;
  SeqObjVector gerewindvec_template;
  SeqObjVector gerewindvec_grappa;
  SeqObjList gepart;
  SeqObjList gepart_template;
  SeqObjList gepart_grappa;
  SeqDelay   gepart_dummy;

  SeqObjVector serewindvec;
  SeqObjVector serewindvec_template;
  SeqObjVector serewindvec_grappa;
  SeqObjList separt;
  SeqObjList separt_template;
  SeqObjList separt_grappa;
  SeqDelay   separt_dummy;

  SeqObjList scan;
  SeqObjList templatepart;
  SeqObjList grappapart;
  SeqObjList imagingpart;
  SeqObjList dummypart;
  SeqObjList slicepart;
  SeqObjList slicepart_dummy;
  SeqObjList slicepart_template;
  SeqObjList slicepart_grappa;
  SeqObjList preppart;



  SeqDelay   exc2acq;
  SeqDelay   exc2refoc;
  SeqDelay   refoc2acq;
  SeqGradConstPulse spoiler;
  SeqTrigger trigger;

  SeqGradTrapezParallel crusher;
  SeqDelay   crusherdelay;

  SeqDiffWeight fw;
  SeqGradTrapez fw1st;
  SeqGradTrapezParallel fw2nd_reph;
  SeqObjList    fwpart;
  SeqDelay      fwmid;


  SeqObjLoop bladeloop;
  SeqRotMatrixVector bladerot;
  dvector bladeangels;

  SeqFieldMap fmapscan;



public:

// This constructor creates an empty EPI sequence
METHOD_CLASS(const STD_string& label) : SeqMethod(label) {
  set_description("Multi-gradient-Echo Single-shot Sampling of Echo Refocussing (MESSER), a combined gradient- and spin-echo sequence using parallel imaging.");
}


void method_pars_init() {

  // In this function, parameters are initialized and default values are set

  commonPars->set_MatrixSize(readDirection,64);
  commonPars->set_MatrixSize(phaseDirection,64,noedit);
  commonPars->set_NumOfRepetitions(1);
  commonPars->set_RepetitionTime(1000.0);
  commonPars->set_AcqSweepWidth(100.0);
  commonPars->set_ReductionFactor(3);

  NumOfEchoes=3;
  NumOfEchoes.set_description("Number of echoes per period");
  append_parameter(NumOfEchoes,"NumOfEchoes");

  SEAcquisition=true;
  SEAcquisition.set_description("Sample the spin echo directly with the last EPI");
  append_parameter(SEAcquisition,"SEAcquisition");

  Blades=1;
  Blades.set_description("Number of long-axis PROPELLER blades");
  append_parameter(Blades,"Blades");

  Shots=1;
  Shots.set_description("Number of shots, multi-shot (segmented) EPI if Shots>1");
  append_parameter(Shots,"Shots");

  PulseDur=4.0; // start with large duration so that sequence can be loaded
  PulseDur.set_unit(ODIN_TIME_UNIT);
  PulseDur.set_description("Pulse duration of excitation and refocusing pulse");
  append_parameter(PulseDur,"PulseDur");

  RampSampling=false;
  RampSampling.set_description("Perform sampling during gradient ramps");
  append_parameter(RampSampling,"RampSampling");

  FatSaturation=true;
  FatSaturation.set_description("Saturation of fat resonance prior to excitation");
  append_parameter(FatSaturation,"FatSaturation");

  fMRITrigger=true;
  fMRITrigger.set_description("External triggering");
  append_parameter(fMRITrigger,"fMRITrigger");

  FWbVal=0.0;
  FWbVal.set_unit("s/mm^2");
  FWbVal.set_description("b-Value of Weak flow weighting after excitation");
  append_parameter(FWbVal,"FWbVal");

  FieldMap=false;
  FieldMap.set_description("Fieldmap pre-scan for distortion correction");
  append_parameter(FieldMap,"FieldMap");

  fmapscan.init("fmapscan");
  append_parameter(fmapscan.get_parblock(),"FieldMapPars");



  TEs.resize(2*NumOfEchoes);
  TEs.set_description("Echo times");
  append_parameter(TEs,"TEs");

}



void method_seq_init() {
  Log<Seq> odinlog(this,"method_seq_init");

  if(NumOfEchoes<2) NumOfEchoes=2;

  ///////////////// Pulses: /////////////////////

  float slicethick=geometryInfo->get_sliceThickness();
  float slicegap=geometryInfo->get_sliceDistance()-slicethick;

  // excitation pulse
  exc=SeqPulsarSinc("exc",slicethick,false,PulseDur,commonPars->get_FlipAngle());
  exc.set_freqlist( systemInfo->get_gamma() * exc.get_strength() / (2.0*PII) * geometryInfo->get_sliceOffsetVector() );
  exc.set_pulse_type(excitation);

  // Slightly thicker refocusing slice for better SNR
  // Since the same spatial resolution is used for exc and refoc, the gradient strengths will be the same
  float extra_slicethick_refoc=STD_min(0.5*slicethick, 0.3*slicegap);

  // refocusing pulse
  refoc=SeqPulsarSinc("refoc",slicethick+extra_slicethick_refoc,false,PulseDur,180.0);
  refoc.set_freqlist( systemInfo->get_gamma() * refoc.get_strength() / (2.0*PII) * geometryInfo->get_sliceOffsetVector() );
  if(!commonPars->get_RFSpoiling()) refoc.set_phase(90.0);
  refoc.set_pulse_type(refocusing);

  // fat saturation pulse
  fatsat=SeqSat("fatsat",fat);



  //////////////// EPI-Readout: //////////////////////////////

  // set equivalent resolution in read and phase direction
  float resolution=secureDivision(geometryInfo->get_FOV(readDirection),commonPars->get_MatrixSize(readDirection));

  int pelines=int(secureDivision(geometryInfo->get_FOV(phaseDirection),resolution)+0.5);
  commonPars->set_MatrixSize(phaseDirection, pelines, noedit);
  float pefov=geometryInfo->get_FOV(phaseDirection);

  if(Blades>1) {
    pelines=int(0.5*PII*commonPars->get_MatrixSize(readDirection)/Blades+0.5);
    pefov=geometryInfo->get_FOV(readDirection); // quadratic FOV
    commonPars->set_MatrixSize(phaseDirection,commonPars->get_MatrixSize(readDirection),noedit); // quadratic size
  }

  float os_read=1.25; // slight oversampling to allow off-center FOV
  if(Blades>1) os_read=2.0;

  ge_epi=SeqAcqEPI("ge_epi",commonPars->get_AcqSweepWidth(),
                   commonPars->get_MatrixSize(readDirection),  geometryInfo->get_FOV(readDirection),
                   pelines, pefov,
                   Shots, commonPars->get_ReductionFactor(), os_read, "",0,0,linear,RampSampling,1.0,commonPars->get_PartialFourier());



  // Phase-correction template
  ge_epi_template=ge_epi;
  ge_epi_template.set_label("ge_epi_template");
  ge_epi_template.set_template_type(phasecorr_template);


  // Full multi-shot EPI readout as GRAPPA training data
  ge_epi_grappa=ge_epi;
  ge_epi_grappa.set_label("ge_epi_grappa");
  ge_epi_grappa.set_template_type(grappa_template);

  se_epi=ge_epi;
  se_epi_template=ge_epi_template;
  se_epi_grappa=ge_epi_grappa;



  // EPI pre-dephase gradient
  ge_deph=SeqAcqDeph("ge_deph",ge_epi,FID);
  se_deph=SeqAcqDeph("se_deph",se_epi,FID);
  deph_template=SeqAcqDeph("deph_template",ge_epi_template,FID);
  ge_deph_grappa=SeqAcqDeph("ge_deph_grappa",ge_epi_grappa,FID);
  se_deph_grappa=SeqAcqDeph("se_deph_grappa",se_epi_grappa,FID);

  // EPI post-rephase gradients
  ge_reph=SeqAcqDeph("ge_reph",ge_epi,rephase);
  se_reph=SeqAcqDeph("se_reph",se_epi,rephase);
  reph_template=SeqAcqDeph("reph_template",ge_epi_template,rephase);
  ge_reph_grappa=SeqAcqDeph("ge_reph_grappa",ge_epi_grappa,rephase);
  se_reph_grappa=SeqAcqDeph("se_reph_grappa",se_epi_grappa,rephase);


  // EPI rewinder after each echo
  fvector gradint(3);

  float rewind_strength=0.4*systemInfo->get_max_grad(); // OK for stimulation monitor 

  gradint=ge_reph.get_gradintegral()+ge_deph.get_gradintegral(); // collapse rephase and dephase into one gradient pulse
  rewind=SeqGradTrapezParallel("rewind",gradint[0],gradint[1],gradint[2],rewind_strength);

  gradint=reph_template.get_gradintegral()+deph_template.get_gradintegral();
  rewind_template=SeqGradTrapezParallel("rewind_template",gradint[0],gradint[1],gradint[2],rewind_strength);

  ODINLOG(odinlog,significantDebug) << "rewind/rewind_template.get_duration()=" << rewind.get_duration() << "/" << rewind_template.get_duration() << STD_endl;

  rewind_paddelay=SeqDelay("rewind_paddelay",rewind.get_duration()-rewind_template.get_duration());



  /////////////////// Rotation of Blades ////////////////////////////////////////////////

  bladerot=SeqRotMatrixVector("bladerot");

  if(Blades>1) {

    bladeangels.resize(Blades);
    for(int iblade=0; iblade<Blades; iblade++) {
      RotMatrix rm("rotmatrix"+itos(iblade));
      float ang=float(iblade)/float(Blades)*PII; // 0...180 deg
      rm.set_inplane_rotation(ang);
      bladeangels[iblade]=ang;
      bladerot.append(rm);
    }

  } else {
    bladerot.append(RotMatrix("identity"));
  }



  /////////////////// RF Spoiling ///////////////////////////////////////////////////////

  if(commonPars->get_RFSpoiling()) {

     // recommended by Goerke et al., NMR Biomed. 18, 534-542 (2005)
    int plistsize=16;
    double plistincr=45.0;

    exc.set_phasespoiling(plistsize, plistincr);
    refoc.set_phasespoiling(plistsize, plistincr, 90.0);

    ge_epi.set_phasespoiling(plistsize, plistincr);
    ge_epi_template.set_phasespoiling(plistsize, plistincr);
    ge_epi_grappa.set_phasespoiling(plistsize, plistincr);

    se_epi.set_phasespoiling(plistsize, plistincr);
    se_epi_template.set_phasespoiling(plistsize, plistincr);
    se_epi_grappa.set_phasespoiling(plistsize, plistincr);


    phaseiter=SeqVecIter("phaseiter");
    phaseiter.add_vector(exc.get_phaselist_vector());
    phaseiter.add_vector(refoc.get_phaselist_vector());
    phaseiter.add_vector(ge_epi.get_phaselist_vector());
    phaseiter.add_vector(ge_epi_template.get_phaselist_vector());
    phaseiter.add_vector(ge_epi_grappa.get_phaselist_vector());
    phaseiter.add_vector(se_epi.get_phaselist_vector());
    phaseiter.add_vector(se_epi_template.get_phaselist_vector());
    phaseiter.add_vector(se_epi_grappa.get_phaselist_vector());

  }


  //////////////// Loops: //////////////////////////////

  // loop to iterate over slices  
  sliceloop=SeqObjLoop("sliceloop");

  // loop to iterate over repetitions
  reploop=SeqObjLoop("reploop");

  // loop to iterate over segments
  segloop=SeqObjLoop("segloop");

  // loop to iterate over GRAPPA interleaves
  grappaloop=SeqObjLoop("grappaloop");

  // loop to iterate over EPI modules
  echoloop=SeqObjLoop("echoloop");

  // loop to iterate over dummy cycles
  dummyloop=SeqObjLoop("dummyloop");

  // loop over zoom sats
//  zoomloop=SeqObjLoop("zoomloop");

  // loop to iterate over PROPELLER blades
  bladeloop=SeqObjLoop("bladeloop");


  //////////////// Timing Delays: //////////////////////////////

  // TR delay
  trdelay=SeqDelay("trdelay");


  //////////////// Spoiler Gradient: //////////////////////////////

  float spoiler_strength=0.5*systemInfo->get_max_grad();
  float spoiler_integral=4.0*fabs(ge_deph.get_gradintegral().sum());
  float spoiler_dur=secureDivision(spoiler_integral,spoiler_strength);

  spoiler=SeqGradConstPulse("spoiler",sliceDirection,spoiler_strength,spoiler_dur);


  //////////////// Crusher Gradient: //////////////////////////////

  float crusher_strength=0.3*systemInfo->get_max_grad(); // Moderate strength to avoid problems with stimulation
  float crusher_integral=2.0*spoiler_integral;
  crusher=SeqGradTrapezParallel("crusher",crusher_integral,crusher_integral,crusher_integral, crusher_strength);

  crusherdelay=SeqDelay("crusherdelay",1.0); // Small delay to avoid gradient-induced stimulation


  //////////////// Flow Weighting: //////////////////////////////

  // reset
  fwpart.clear();

  if(FWbVal>0.0) {

    fwmid=SeqDelay("fwmid",1.0); // Small delay to avoid nerve stimulation

    fvector bVals(1);
    bVals[0]=1000.0*FWbVal;
    fw=SeqDiffWeight("fw", bVals, 0.8*systemInfo->get_max_grad(), fwmid, sliceDirection);

    // Combine slice rephaser and flow weighting
    float fwint=fw.get_grad1().get_gradintegral()[sliceDirection]+exc.get_reph_gradintegral()[sliceDirection];

    fw1st=SeqGradTrapez("fw1st", fwint, sliceDirection, fw.get_grad1().get_gradduration());

//    fw2nd=SeqGradTrapez("fw2nd", fw.get_grad2().get_gradintegral()[sliceDirection], sliceDirection, fw.get_grad2().get_gradduration());
    fw2nd_reph=SeqGradTrapezParallel("fw2nd_reph",0.0,0.0,fw.get_grad2().get_gradintegral()[sliceDirection],fw1st.get_strength());

    fwpart=fw1st+fwmid+fw2nd_reph;

  } else {

    fw2nd_reph=SeqGradTrapezParallel("fw2nd_reph",0.0,0.0,exc.get_reph_gradintegral()[sliceDirection],0.8*systemInfo->get_max_grad());

    fwpart=fw2nd_reph;
  }



  //////////////// fMRI trigger: //////////////////////////////

  trigger=SeqTrigger("fmri_trigger",1.0);

  //////////////// Field-map template: //////////////////////////////

  if(FieldMap) {
    if(FatSaturation) fmapscan.build_seq(commonPars->get_AcqSweepWidth(),1.0,fatsat); // pass fat saturation on to field-map scan
    else              fmapscan.build_seq(commonPars->get_AcqSweepWidth(),1.0);
  }


  //////////////// Build the sequence: //////////////////////////////


  // add fat saturation to template and repetitions
  if(FatSaturation) preppart += fatsat;


  if(fMRITrigger) slicepart += trigger;



  // GE part
  ivector ge_iv(NumOfEchoes);
  int i;
  for(i=0; i<NumOfEchoes; i++) {
    if(i<(NumOfEchoes-1)) {
      gerewindvec          += rewind;
      gerewindvec_template += rewind_template+rewind_paddelay;
      gerewindvec_grappa   += rewind; // Rewind is the same for actual scan and GRAPPA
    } else {
      gerewindvec          += ge_reph        / spoiler;
      gerewindvec_template += reph_template  / spoiler;
      gerewindvec_grappa   += ge_reph_grappa / spoiler;
    }
    ge_iv[i]=i; // Assign index 0-(NumOfEchoes-1) to GE part
  }
  gerewindvec.set_indexvec(ge_iv);
  gerewindvec_template.set_indexvec(ge_iv);
  gerewindvec_grappa.set_indexvec(ge_iv);


  // SE part
  int nechoes_se=NumOfEchoes;
  ivector se_iv(nechoes_se);
  for(i=0; i<(nechoes_se); i++) {
    if(i<(nechoes_se-1)) {
      serewindvec          += rewind;
      serewindvec_template += rewind_template+rewind_paddelay;
      serewindvec_grappa   += rewind; // Rewind is the same for actual scan and GRAPPA
    } else {
      serewindvec          += se_reph;
      serewindvec_template += reph_template;
      serewindvec_grappa   += se_reph_grappa;
    }
    se_iv[i]=NumOfEchoes+i; // Assign index NumOfEchoes-(3*NumOfEchoes-1) to SE part
  }
  serewindvec.set_indexvec(se_iv);
  serewindvec_template.set_indexvec(se_iv);
  serewindvec_grappa.set_indexvec(se_iv);


  // Balanced multi-echo EPI trains
  gepart          = ge_deph +       echoloop(ge_epi          + gerewindvec          )[gerewindvec];
  gepart_template = deph_template + echoloop(ge_epi_template + gerewindvec_template )[gerewindvec_template];
  gepart_grappa   = ge_deph_grappa +echoloop(ge_epi_grappa   + gerewindvec_grappa   )[gerewindvec_grappa];
  gepart_dummy = SeqDelay("gepart_dummy", gepart.get_duration());

  separt          = se_deph +       echoloop(se_epi          + serewindvec          )[serewindvec];
  separt_template = deph_template + echoloop(se_epi_template + serewindvec_template )[serewindvec_template];
  separt_grappa   = se_deph_grappa +echoloop(se_epi_grappa   + serewindvec_grappa   )[serewindvec_grappa];
  separt_dummy = SeqDelay("separt_dummy", separt.get_duration());


  if(Blades>1) {
    gepart.         set_gradrotmatrixvector(bladerot);
    gepart_template.set_gradrotmatrixvector(bladerot);
    gepart_grappa.  set_gradrotmatrixvector(bladerot);
    separt.         set_gradrotmatrixvector(bladerot);
    separt_template.set_gradrotmatrixvector(bladerot);
    separt_grappa.  set_gradrotmatrixvector(bladerot);
  }


  sedelay=SeqDelay("sedelay",0.0);

  imagingpart=  preppart + exc + fwpart + gepart          + refoc + spoiler + sedelay + separt          + crusherdelay + crusher + crusherdelay;

  dummypart=    preppart + exc + fwpart + gepart_dummy    + refoc + spoiler + sedelay + separt_dummy    + crusherdelay + crusher + crusherdelay;

  templatepart= preppart + exc + fwpart + gepart_template + refoc + spoiler + sedelay + separt_template + crusherdelay + crusher + crusherdelay;

  grappapart=   preppart + exc + fwpart + gepart_grappa   + refoc + spoiler + sedelay + separt_grappa   + crusherdelay + crusher + crusherdelay;


  slicepart +=         sliceloop( imagingpart + trdelay  )[exc][refoc];

  slicepart_dummy =    sliceloop( dummypart   + trdelay  )[exc][refoc];

  slicepart_template = sliceloop( templatepart + trdelay )[exc][refoc];

  slicepart_grappa  =  sliceloop( grappapart + trdelay   )[exc][refoc];

  if(commonPars->get_RFSpoiling()) {
    slicepart += phaseiter;
    slicepart_dummy += phaseiter;
    slicepart_template += phaseiter;
    slicepart_grappa += phaseiter;
  }


  if(FieldMap) scan += fmapscan + trdelay;

  scan += dummyloop( slicepart_dummy )[3];


  // template scan for phase correction
  scan+= bladeloop(
           slicepart_template
         )[bladerot];


  if(commonPars->get_ReductionFactor()>1) {
    // Fully sampled k-space
    scan+= grappaloop(
             bladeloop(
               segloop(
                 slicepart_grappa
               )[ge_deph_grappa.get_epi_segment_vector()][ge_reph_grappa.get_epi_segment_vector()][se_deph_grappa.get_epi_segment_vector()][se_reph_grappa.get_epi_segment_vector()]
             )[bladerot]
           )[ge_deph_grappa.get_epi_reduction_vector()][ge_reph_grappa.get_epi_reduction_vector()][se_deph_grappa.get_epi_reduction_vector()][se_reph_grappa.get_epi_reduction_vector()];
  }


  // actual scan loop
  scan+= reploop(
           bladeloop(
             segloop(
               slicepart
             )[ge_deph.get_epi_segment_vector()][se_deph.get_epi_segment_vector()][ge_reph.get_epi_segment_vector()][se_reph.get_epi_segment_vector()]
           )[bladerot]
         )[commonPars->get_NumOfRepetitions()];


  set_sequence( scan );
}




void method_rels() {
  Log<Seq> odinlog(this,"method_rels");


  double TEexc= exc.get_duration() - exc.get_magnetic_center() + fwpart.get_duration();
  ODINLOG(odinlog,significantDebug) << "TEexc=" << TEexc << STD_endl;


  // Fixed TE according to GE part
  double TEhalf = TEexc
             + gepart.get_duration()
//             + spoiler.get_duration()
             + refoc.get_magnetic_center();

  commonPars->set_EchoTime(2.0*TEhalf);


  int nechoes_se=NumOfEchoes;
  TEs.resize(NumOfEchoes+nechoes_se);

  double TEdeph=ge_deph.get_duration();
  double TEepi=ge_epi.get_duration()+rewind.get_duration();
  double TEacq=ge_epi.get_acquisition_center();
  ODINLOG(odinlog,significantDebug) << "TEdeph/TEepi/TEacq=" << TEdeph << "/" << TEepi << "/" << TEacq << STD_endl;

  // GE echo times
  int i;
  for(i=0; i<NumOfEchoes; i++) {
    TEs[i]=TEexc+TEdeph+float(i)*TEepi+TEacq;
    ODINLOG(odinlog,significantDebug) << "TEs[" << i << "]=" << TEs[i] << STD_endl;
  }

  double TErefoc=refoc.get_duration() - refoc.get_magnetic_center() + spoiler.get_duration();

  // SE echo times  
  for(i=0; i<nechoes_se; i++) {
    TEs[NumOfEchoes+i]=TEhalf+TErefoc+TEdeph+float(i)*TEepi+TEacq;
  }

  // Check placement of SE echo times
  for(i=0; i<NumOfEchoes; i++) {
    if(TEs[NumOfEchoes+i]>commonPars->get_EchoTime()) {
      ODINLOG(odinlog,errorLog) << "TE[" << (NumOfEchoes+i) << "] too late by " << fabs(TEs[NumOfEchoes+i]-commonPars->get_EchoTime()) << STD_endl;
    }
  }

  if(SEAcquisition) {
    double tediff=commonPars->get_EchoTime()-TEs[2*NumOfEchoes-1];
    sedelay=tediff;
    for(i=0; i<nechoes_se; i++) TEs[NumOfEchoes+i]+=tediff;
  }


  ////////////////// TR Timings: ////////////////////////////////

  float slicedur=slicepart.get_duration();
  if(commonPars->get_RepetitionTime()<slicedur) commonPars->set_RepetitionTime(slicedur);
  trdelay=(commonPars->get_RepetitionTime()-slicedur)/double(geometryInfo->get_nSlices());

}


void method_pars_set() {

  // extra information for the automatic reconstruction
  ge_epi.         set_reco_vector(slice,exc);
  ge_epi_template.set_reco_vector(slice,exc);
  ge_epi_grappa.  set_reco_vector(slice,exc);
  se_epi.         set_reco_vector(slice,exc);
  se_epi_template.set_reco_vector(slice,exc);
  se_epi_grappa.  set_reco_vector(slice,exc);

  // Index for TEs
  ge_epi.         set_reco_vector(userdef,gerewindvec);
  ge_epi_template.set_reco_vector(userdef,gerewindvec_template);
  ge_epi_grappa.  set_reco_vector(userdef,gerewindvec_grappa);
  se_epi.         set_reco_vector(userdef,serewindvec);
  se_epi_template.set_reco_vector(userdef,serewindvec_template);
  se_epi_grappa.  set_reco_vector(userdef,serewindvec_grappa);
  recoInfo->set_DimValues(userdef,TEs);

  if(Blades>1) {
    ge_epi.         set_reco_vector(cycle,bladerot);
    ge_epi_template.set_reco_vector(cycle,bladerot);
    ge_epi_grappa.  set_reco_vector(cycle,bladerot);
    se_epi.         set_reco_vector(cycle,bladerot);
    se_epi_template.set_reco_vector(cycle,bladerot);
    se_epi_grappa.  set_reco_vector(cycle,bladerot);
    recoInfo->set_DimValues(cycle,bladeangels);
  }


  recoInfo->set_PostProc3D("usercoll | messer");

  int driftcorrte=NumOfEchoes-1;
  recoInfo->set_CmdLineOpts("-ff Hamming -fp 0.8 -dcs userdef="+itos(driftcorrte)+" -dce "+ftos(TEs[driftcorrte]));

}

};

/////////////////////////////////////////////////////


// entry point for the sequence module
ODINMETHOD_ENTRY_POINT
