-------------------------------------------------------------------------------
--                                                                           --
--                          Experiment Source Code                           --
--              Delta NMR Experiment & Machine Control Interface             --
--                                                                           --
--                     Copyright (c) 2021 JEOL Ltd                           --
--                            All Rights Reserved                            --
--                                                                           --
-------------------------------------------------------------------------------
-- HELP.eng: GEMSTONE CLIP-COSY
-- Category: 1D, CLIP-COSY, GEMSTONE,liquid_advanced
-- File name : GEMSTONE_CLIP-COSY
--
-- Sequence name : GEMSTONE CLIP-COSY
--
-- References :
-- [1] P. Kiraly et al, Angew. Chem. Int. Ed., 2021, 60, 666-669.
-- [2] P. Kiraly et al, Chem. Commun., 2021, 57, 2368-2371.
-- [3] D. Taylor et al, Chem. Commun., 2023, in press. 
--
-- Parameters
-- x_pulse          : 90[deg] pulse width
-- x_atn            : attenuator of x_pulse
--
-- obs_sel_180      : 180[deg] selective pulse
-- obs_sel_offset   : offset for obs_sel_180
-- obs_sel_atn      : attenuator of obs_sel_180
-- obs_sel_shape    : pulse shape of obs_sel_180
--
--
-- relaxation_delay : inter-pulse delay
-- repetition_time  : pulse repetition_time (= relaxation_delay+x_acq_time)
--
--
-- dante_presat     : select TRUE or FALSE for obs_dante_presaturation.
-- irr_mode         : select irr_mode, "OFF","Presaturation" or "Homo Decouple".
-- tri_mode         : select tri_mode, "OFF","Presaturation" or "Homo Decouple".
-- presat_time      : duration of dante presaturation.
--
-- dante parameters
--
-- dante_pulse      : pulse width of dante presaturation
-- dante_interval   : pulse interval of dante presaturation
-- dante_attenuator : attenuator of dante presaturation
-- dante_loop       : real loop number/100
--
-- irr/tri decoupling parameters
--
-- irr_domain       : nucleus of irr presaturation or homo_decoupling
-- irr_offset       : offset of irr presaturation or homo_decoupling
-- irr_attenuator   : attenuator of irr presaturation or homo_decoupling
--
-- tri_domain       : nucleus of tri presaturation or homo_decoupling
-- tri_offset       : offset of tri presaturation or homo_decoupling
-- tri_attenuator   : attenuator of tri presaturation or homo_decoupling
--
-- Note :
-- scans = 16*n
--
-- x90-PFG1-sel180-PFG1-PFG2-sel180-PFG2-mix_time-acq
-- PFG1 not = PFG2
--
--
-- END HELP

header
    filename        => "GEMSTONE_CLIP-COSY";
    sample_id       => "";
    comment         => "GEMSTONE CLIP-COSY";
    process         =  "proton_autophase.list";
    auto_dwell      =  TRUE;
    auto_filter     =  TRUE;
    auto_gain       => FALSE;
    filter_limit    =  12;
    force_dual_mode => FALSE;
    decimation_rate =  0;
    force_tune      => FALSE;
    power_2         =  FALSE;
    round_points    =  FALSE;
    save_aborted    =  TRUE;
    vector          =  TRUE;
    mod_save        => 0;
end header;

instrument
    recvr_gain          => 50;
    get_90              =  "pulse_service::get_90_value";
    get_atn             =  "pulse_service::get_atn_value";
    get_freq            =  "pulse_service::get_freq_value";
    get_spin            =  "pulse_service::get_spin";
    get_gamma           =  "pulse_service::get_gamma";
    get_value_of_field  =  "pulse_service::get_value_of_field";
    get_probe_parameter =  "probe_service::get_probe_parameter";
    get_s_mparam        =  "pulse_service::get_s_mparam";
    get_d_mparam        =  "pulse_service::get_d_mparam";
    spin_state          => "SPIN OFF";
end instrument;

acquisition
    x_domain             => "Proton";
    x_offset             => 5[ppm];
    x_sweep              => 18[ppm];
    default_x_resolution =  _get_value_of_field(x_domain, "x_1D_resolution");
    x_data_points        =  _get_value_of_field(x_domain, "x_data_points");
    x_points_default     =? if upper (x_sweep / default_x_resolution) > x_data_points
                            then x_data_points
                            else upper (x_sweep / default_x_resolution);
    x_points             => 16384;
    scans                => 32, help "scans = 4*n";
    x_prescans           => 4;
    mod_return           => 8;
    x_acq_time           =? x_points / x_sweep;
    x_resolution         =? 1 / x_acq_time;
    x_sweep_input        =  lower (x_sweep * transition_ratio / _get_freq(x_domain) * 1[Mppm]);
    x_points_input       =  lower (x_points * transition_ratio);
end acquisition;

pulse
    collect COMPLEX,OBS;

    macro obs_presat_time( dante_presat, dante_loop, dante_pulse, dante_interval, phase_dante, phs_shft, dante_attenuator, presat_time ) is
        when dante_presat do
            loop 100 * dante_loop times
                dante_pulse, (OBS.GATE, OBS.PHS.phase_dante.lstep(phs_shft), OBS.ATN.dante_attenuator);
                dante_interval;
            end loop;
        end when;
        when not dante_presat do
            presat_time;
        end when;
    end obs_presat_time;

    macro acq( dead_time, delay, phase ) is
        dead_time, OBS.PHS.0;
        delay, (OBS.PHS.0, RCV.GATE);
        acquire (OBS.PHS.0, RCV.PHS.phase);
    end acq;

    experiment               =  "GEMSTONE_clip-cosy.jxp";
    obs_domain               =  x_domain;
    obs_offset               =  x_offset;
    obsfreq                  =  _get_freq(obs_domain);
    comment_1                =? "*** Pulse ***";
    x_pulse                  => x90, help "observe 90[deg] pulse";
    x_atn                    =? xatn, help "attenuator for x_pulse";
    obs_pulse                =  x_pulse;
    obs_atn                  =  x_atn;
    comment_56               =? "*** GEMSTONE ***";
    obs_chpgs_shape          => "CHIRP", ad_shape_names, help "shape pulse";
    obs_chpgs_m_pulse        => 50[ms], help "ZQfilter pulse width";
    obs_chpgs_m_fsweep       => 2.5[kHz];
    obs_chpgs_sweep_ppm      =  obs_chpgs_m_fsweep / obsfreq * 1[Mppm];
    obs_chpgs_chirp_smooth   => 10[%];
    obs_chpgs_m_q0           => 11, help "q0 >= 11";
    obs_chpgs_m_ph_rev       =  1;
    obs_chpgs_b1_calc        =  sqrt (obs_chpgs_m_q0 * obs_chpgs_m_fsweep / (6.28319 * obs_chpgs_m_pulse));
    obs_chpgs_m_b1max        => obs_chpgs_b1_calc;
    obs_chpgs_pw90           =  1 / (4 * obs_chpgs_m_b1max);
    obs_chpgs_atn_calc       =  obs_atn + 20[dB] * log (obs_chpgs_pw90 / obs_pulse);
    obs_chpgs_atn            => obs_chpgs_atn_calc;
    obs_chpgs2_m_fsweep      =  obs_chpgs_m_fsweep;
    obs_chpgs2_m_pulse       =  obs_chpgs_m_pulse;
    obs_chpgs2_chirp_smooth  =  obs_chpgs_chirp_smooth;
    obs_chpgs2_m_q0          =  obs_chpgs_m_q0;
    obs_chpgs2_m_ph_rev      =  -1, (1, -1), help "phase reverse";
    obs_chpgs2_atn           =  obs_chpgs_atn_calc;
    grad_sl1                 =? obs_chpgs_m_pulse;
    grad_sl1_amp             => 2.5[mT/m], help "Amplitude of gradient during 1st chirp";
    grad_sl2                 =  obs_chpgs_m_pulse;
    grad_sl2_amp             =? -1 * grad_sl1_amp, help "Amplitude of gradient during 2nd chirp";
    grad_shape_type          => "SQUARE", fg_shape_names, help "gradient shape";
    comment_32               =? "*** Selective Pulse 180deg  ***";
    obs_sel_shape            => "RSNOB_180", std_shape_names, help "shape of obs_sel_180";
    soft_shape_input         =  obs_sel_shape;
    obs_sel_offset           =? x_offset, help "offset of obs_sel_180";
    soft_bw_input            => 100[Hz], help "bandwidth in [ppm] or [Hz] of obs_sel_180";
    xfreq                    =  _get_freq(x_domain);
    soft_angle               =? _get_s_mparam(soft_shape_input, "m_angle", 90[deg]);
    int_soft_pc              =  _get_s_mparam(soft_shape_input, "m_integ", 100[%]);
    int_r_soft_pc            =  int_soft_pc / _get_s_mparam("gauss_90", "m_integ", 100[%]);
    unit_soft_pc             =  if soft_bw_input * 0 = 0[ppm]
                                then 1
                                else if soft_bw_input * 0 = 0[Hz]
                                then 2
                                else 3;
    soft_bw_hz               =  if unit_soft_pc = 1
                                then soft_bw_input * xfreq / 1[Mppm]
                                else if unit_soft_pc = 2
                                then soft_bw_input
                                else 1[Hz];
    type_soft_pc             =  _get_s_mparam(soft_shape_input, "m_type", "std");
    is_std_pc                =  if type_soft_pc = "std" and unit_soft_pc < 3
                                then TRUE
                                else FALSE;
    soft_pw_calc             =? if is_std_pc
                                then _get_s_mparam(soft_shape_input, "bw", 1) / soft_bw_hz
                                else 1[us];
    soft_atn_calc            =? if is_std_pc
                                then xatn_soft + 20[dB] * log (soft_pw_calc / x90_soft * 90[deg] / soft_angle * int_r_soft_pc)
                                else 79[dB];
    obs_sel_180              => soft_pw_calc, help "selective 180[deg] pulse";
    obs_sel_atn              => soft_atn_calc, help "attenuator of obs_sel_180";
    obs_sel_slp              =  obs_sel_offset;
    comment_50               =? "*** CLIP-COSY ***";
    delta                    => 15[ms], help "transfer delay for CLIP-COSY";
    initial_wait             =  1[s];
    rpt_min                  =  x_points * filter_limit * 3.64[us] + 10[ms];
    rpt_def_temp             =  if x_domain = "Proton"
                                then 7[s]
                                else if x_domain = "Fluorine19"
                                then 7[s]
                                else if x_domain = "Carbon13"
                                then 3[s]
                                else 5[s];
    rd_def_temp              =  if rpt_def_temp - x_acq_time > 0.1[s]
                                then rpt_def_temp - x_acq_time
                                else 0.1[s];
    relaxation_delay_default =  if rpt_def_temp > rpt_min
                                then rd_def_temp
                                else if rpt_min - x_acq_time > 0[s]
                                then rpt_min - x_acq_time
                                else 0.1[s];
    relaxation_delay         => 0.5[s], help "inter-pulse delay";
    repetition_time          =? relaxation_delay + x_acq_time, help "relaxation_delay+x_acq_time";
    comment_8                =? "*** Pulse Field Gradient ***";
    gradient_max             =? z_gradient_max, help "Maximum amplitude for a given probe as defined in the probe file";
    grad_1                   => 1[ms], help "pulse width of PFG1";
    grad_1_amp               => 0.1[T/m], help "amplitude of PFG1(not = PFG2)";
    grad_2                   =  grad_1, help "pulse width of PFG2";
    grad_2_amp               => 60[mT/m], help "amplitude of PFG2(not = PFG1)";
    grad_shape               => "SQUARE", fg_shape_names, help "shape of gradients";
    grad_recover             => 0.2[ms];
    grad_recover_zq          => 5[ms];
    comment_41               =? "*** Zero-Quantum Dephasing ***";
    obs_chp_shape            =? "CHIRP", ad_shape_names, help "shape pulse";
    obs_chp1_m_pulse         => 50[ms], (30[ms], 40[ms], 50[ms]), help "ZQfilter pulse width";
    obs_chp1_m_fsweep        =? if obs_chp1_m_pulse = 30[ms]
                                then x_sweep * 2
                                else if obs_chp1_m_pulse = 40[ms]
                                then x_sweep * 2
                                else x_sweep * 2;
    obs_chp1_sweep_ppm       =? round (obs_chp1_m_fsweep * 1[Mppm] / obsfreq), help "obs_chp1_ad_sweep_ppm";
    obs_chp1_chirp_smooth    =  10[%];
    obs_chp1_m_q0            =  5, help "q >= 5 On resonance adiabatic Quality factor";
    obs_chp1_m_ph_rev        =  1, (1, -1), help "phase reverse";
    obs_chp1_b1_calc         =  sqrt (obs_chp1_m_q0 * obs_chp1_m_fsweep / (6.28319 * obs_chp1_m_pulse));
    obs_chp1_m_b1max         =? obs_chp1_b1_calc;
    obs_chp1_pw90            =  1 / (4 * obs_chp1_m_b1max);
    obs_chp1_atn_calc        =  if obs_atn + 20[dB] * log (obs_chp1_pw90 / obs_pulse) < obs_atn + 6[dB]
                                then obs_atn + 6[dB]
                                else obs_atn + 20[dB] * log (obs_chp1_pw90 / obs_pulse);
    obs_chp1_atn             =? obs_chp1_atn_calc;
    obs_chp2_m_pulse         => 30[ms], (30[ms], 40[ms], 50[ms]), help "ZQfilter pulse width";
    obs_chp2_m_fsweep        =? if obs_chp2_m_pulse = 30[ms]
                                then x_sweep * 2
                                else if obs_chp2_m_pulse = 40[ms]
                                then x_sweep * 2
                                else x_sweep * 2;
    obs_chp2_sweep_ppm       =? round (obs_chp2_m_fsweep * 1[Mppm] / obsfreq), help "obs_chirp2_ad_sweep_ppm";
    obs_chp2_chirp_smooth    =  10[%];
    obs_chp2_m_q0            =  5, help "q >= 5 On resonance adiabatic Quality factor";
    obs_chp2_m_ph_rev        =  1, (1, -1), help "phase reverse";
    obs_chp2_b1_calc         =  sqrt (obs_chp2_m_q0 * obs_chp2_m_fsweep / (6.28319 * obs_chp2_m_pulse));
    obs_chp2_m_b1max         =? obs_chp2_b1_calc;
    obs_chp2_pw90            =  1 / (4 * obs_chp2_m_b1max);
    obs_chp2_atn_calc        =  if obs_atn + 20[dB] * log (obs_chp2_pw90 / obs_pulse) < obs_atn + 6[dB]
                                then obs_atn + 6[dB]
                                else obs_atn + 20[dB] * log (obs_chp2_pw90 / obs_pulse);
    obs_chp2_atn             =? obs_chp2_atn_calc;
    g_factor                 =  1, help "obs_gamma/1H_gamma";
    coil_factor              =  1, help "coil_length/20mm";
    f_factor_zqf1            =  obs_chp1_m_fsweep / 40[kHz], help "ref 10ppm*8/500MHz=40kHz";
    grad_zqf1_amp_calc       =  47[mT/m] * f_factor_zqf1 / coil_factor / g_factor, help "gradient amplitude of grad_sl_ps";
    grad_zqf1_amp            =? grad_zqf1_amp_calc, help "Enter amplitude in Tesla/meter units";
    f_factor_zqf2            =  obs_chp2_m_fsweep / 40[kHz], help "ref 10ppm*8/500MHz=40kHz";
    grad_zqf2_amp_calc       =  47[mT/m] * f_factor_zqf2 / coil_factor / g_factor, help "gradient amplitude of grad_sl_ps";
    grad_zqf2_amp            =? grad_zqf2_amp_calc, help "Enter amplitude in Tesla/meter units";
    comment_900              =? "*** lock hold ***";
    lock_hold                => FALSE, help "select TRUE or FALSE for lock hold";
    comment_201              =? "*** obs_dante_presaturation ***";
    dante_presat             => FALSE, help "True/False for obs_dante_presaturation";
    when dante_presat do
        dante_offset             => x_offset, help "offset of dante presaturation";
        dante_pulse              => 4[us], help "pulse width of dante presaturation";
        dante_interval           => 0.1[ms] - dante_pulse, help "interval of dante pulse train";
        dante90_temp             =  x90;
        danteatn_temp            =  xatn;
        dante_temp               =  dante_pulse / (dante_pulse + dante_interval);
        dante_atn_default        =? danteatn_temp + 20[dB] * log (8.3[ms] * dante_temp / dante90_temp), help "calculate a value of B1=30Hz";
        dante_attenuator         => dante_atn_default, 10[dB]->119[dB] : 10[mdB], help "attenuator of dante presaturation";
        proton_freq              =  _get_freq(x_domain);
        diff_offset              =  (dante_offset - x_offset) * 1[Mppm-1] * proton_freq;
        phs_shft                 =  diff_offset * (dante_pulse + dante_interval) * 360;
        phase_dante              =  {0};
    end when;
    comment_202              =? "*** irr_ presaturation & homo spin decoupling ***";
    irr_mode                 => "Off", ("Off", "Presaturation", "Homo Decouple"), help "Select Presaturation or Homo Decouple";
    when irr_mode = "Homo Decouple" do
        note_irr_homodec         =? "Set [filter_limit = 2-4] in the Header parameters";
    end when;
    when irr_mode /= "Off" do
        irr_domain               =? x_domain, help "nucleus of irr presaturation or homo_decoupling";
        irr_offset               => 5[ppm], help "offset of irr presaturation or homo_decoupling";
        irr90_temp               =  x90;
        irratn_temp              =  xatn;
        irr_atn_default          =? irratn_temp + 20[dB] * log (8.3[ms] / irr90_temp), help "calculate a value of B1=30Hz";
        irr_attenuator           => irr_atn_default, 10[dB]->119[dB] : 10[mdB], help "attenuator of irr presaturation or homo_decoupling";
    end when;
    comment_203              =? "*** tri_ presaturation & homo spin decoupling ***";
    tri_mode                 => "Off", ("Off", "Presaturation", "Homo Decouple"), help "Select Presaturation or Homo Decouple";
    when tri_mode = "Homo Decouple" do
        note_tri_homodec         =? "Set [filter_limit = 2-4] in the Header parameters";
    end when;
    when tri_mode /= "Off" do
        tri_domain               =? x_domain, help "nucleus of tri presaturation or homo_decoupling";
        tri_offset               => 5[ppm], help "offset of tri presaturation or homo_decoupling";
        tri90_temp               =  x90;
        triatn_temp              =  xatn;
        tri_atn_default          =? triatn_temp + 20[dB] * log (8.3[ms] / tri90_temp), help "calc.value of B1=30Hz";
        tri_attenuator           => tri_atn_default, 10[dB]->119[dB] : 10[mdB], help "attenuator of tri presaturation or homo_decoupling";
    end when;
    comment_111              =? "*** presat_time ***";
    presat_time_flag         => FALSE, help "select TRUE or FALSE for using presat_time";
    when presat_time_flag do
        presat_time_temp         => relaxation_delay, help "presaturation_time <= relaxation_delay";
    end when;
    presat_time              =? if relaxation_delay > presat_time_temp
                                then presat_time_temp
                                else relaxation_delay;
    relaxation_delay_calc    =  relaxation_delay - presat_time;
    dante_loop               =  lower (presat_time / (100 * (dante_pulse + dante_interval))), help "real loop number/100";
    dead_time                =  if not auto_dwell
                                then 0.2 / x_sweep
                                else 0[us];
    delay                    =  if not auto_dwell
                                then 0.8 / x_sweep
                                else 0[us];
    phase_1                  =  {16(0), 16(180)};
    phase_2                  =  {0};
    phase_3                  =  {4(0), 4(90), 4(180), 4(270)};
    phase_4                  =  {0};
    phase_5                  =  {2(0), 2(180)};
    phase_6                  =  {0};
    phase_7                  =  {0};
    phase_8                  =  {90};
    phase_9                  =  {90};
    phase_10                 =  {270};
    phase_11                 =  {0};
    phase_12                 =  {0};
    phase_13                 =  {0, 180};
    phase_acq                =  {2(0, 180, 180, 0, 180, 0, 0, 180), 2(180, 0, 0, 180, 0, 180, 180, 0)};
    module_config            =  if irr_mode = "Homo Decouple"
                                then if tri_mode = "Homo Decouple"
                                     then "irr.time_share tri.time_share obs.blank_inhibit"
                                     else "irr.time_share obs.blank_inhibit"
                                else if tri_mode = "Homo Decouple"
                                then "tri.time_share obs.blank_inhibit"
                                else "";
begin
    initial_wait;
    relaxation_delay_calc;
    when irr_mode /= "Off" do
        on (IRR.GATE, IRR.PHS.0, IRR.ATN.irr_attenuator);
    end when;
    when tri_mode /= "Off" do
        on (TRI.GATE, TRI.PHS.0, TRI.ATN.tri_attenuator);
    end when;
    obs_presat_time( dante_presat, dante_loop, dante_pulse, dante_interval, phase_dante, phs_shft, dante_attenuator, presat_time );
    when irr_mode /= "Off" do
        off IRR.GATE;
    end when;
    when tri_mode /= "Off" do
        off TRI.GATE;
    end when;
    when lock_hold do
        on LOCKHOLD;
    end when;
    1[us];
    x_pulse, (OBS.GATE, OBS.PHS.phase_1, OBS.ATN.x_atn);
    3[ms];
    parallel
        justify center
            grad_sl1, (FGZ.GATE, FGZ.AMP.grad_sl1_amp, FGZ.SHAPE."SQUARE");
        justify center
            obs_chpgs_m_pulse, (OBS.GATE, OBS.PHS.phase_2, OBS.ATN.obs_chpgs_atn, OBS.SHAPE.{obs_chpgs_shape, "obs_chpGS"});
    end parallel;
    3[ms];
    grad_1, (FGZ.GATE, FGZ.SHAPE.grad_shape, FGZ.AMP.grad_1_amp);
    grad_recover;
    obs_sel_180, (OBS.GATE, OBS.PHS.phase_3, OBS.ATN.obs_sel_atn, OBS.LAMINAR.obs_sel_slp, OBS.SHAPE.obs_sel_shape);
    grad_1, (FGZ.GATE, FGZ.SHAPE.grad_shape, FGZ.AMP.grad_1_amp);
    grad_recover;
    3[ms];
    parallel
        justify center
            grad_sl2, (FGZ.GATE, FGZ.AMP.grad_sl2_amp, FGZ.SHAPE."SQUARE");
        justify center
            obs_chpgs_m_pulse, (OBS.GATE, OBS.PHS.phase_4, OBS.ATN.obs_chpgs2_atn, OBS.SHAPE.{obs_chpgs_shape, "obs_chpGS2"});
    end parallel;
    3[ms];
    x_pulse, (OBS.GATE, OBS.PHS.phase_5, OBS.ATN.x_atn);
    on (FGZ.GATE, FGZ.AMP.grad_zqf1_amp);
    obs_chp1_m_pulse, (OBS.GATE, OBS.PHS.phase_6, OBS.ATN.obs_chp1_atn, OBS.SHAPE.{obs_chp_shape, "obs_chp1"});
    off (FGZ.GATE, FGZ.AMP.grad_zqf1_amp);
    grad_recover;
    x_pulse, (OBS.GATE, OBS.PHS.phase_7, OBS.ATN.x_atn);
    delta / 2;
    2 * x_pulse, (OBS.GATE, OBS.PHS.phase_8, OBS.ATN.x_atn);
    delta / 2;
    x_pulse, (OBS.GATE, OBS.PHS.phase_9, OBS.ATN.x_atn);
    delta / 2;
    2 * x_pulse, (OBS.GATE, OBS.PHS.phase_10, OBS.ATN.x_atn);
    delta / 2;
    x_pulse, (OBS.GATE, OBS.PHS.phase_11, OBS.ATN.x_atn);
    0.1[ms];
    on (FGZ.GATE, FGZ.AMP.grad_zqf2_amp);
    obs_chp2_m_pulse, (OBS.GATE, OBS.PHS.phase_12, OBS.ATN.obs_chp2_atn, OBS.SHAPE.{obs_chp_shape, "obs_chp2"});
    off (FGZ.GATE, FGZ.AMP.grad_zqf2_amp);
    0.1[ms];
    grad_2, (FGZ.GATE, FGZ.SHAPE.grad_shape, FGZ.AMP.grad_2_amp);
    grad_recover_zq;
    x_pulse, (OBS.GATE, OBS.PHS.phase_13, OBS.ATN.x_atn);
    acq( dead_time, delay, phase_acq );
    when lock_hold do
        off LOCKHOLD;
    end when;
end pulse;
