/*******************************************************************************
* Instrument: SOLEIL_PX2a
*
* %Identification
* Written by: M. Savko and E. Farhi
* Date: 2022-03-23
* Origin: Synchrotron SOLEIL
* %INSTRUMENT_SITE: SOLEIL
*
* The PROXIMA-2a MX beam-line at Synchrotron SOLEIL.
*
* %Description
* PROXIMA 2A (PX2-A) is a microfocus beamline dedicated to biological
* crystallography and innovative micro-beam methodologies. Opened to the
* scientific community since 2013, the topics treated on the beamline go beyond
* standard protein crystallography and include drug discovery, membrane proteins,
* virus crystallography, small molecule crystallography, powder diffraction and
* even crystalluria. The beamline is highly automated and designed to help
* scientists tackle the most challenging structural targets and biological
* systems. The X-ray energy is rapidly tunable over a wide range (6-18 keV) making
* the most commonly used absorption edges accessible for anomalous diffraction
* experiments. The end station is equipped with a high capacity sample-changing
* system (148 SPINE pins), a high performance micro-diffractometer with a
* mini-kappa (MD2), an X-ray fluorescence detector (KETEK), and a fast, low-noise,
* photon-counting, area detector - the EIGER X 9M (238 fps in 9M mode, 750 fps in
* 4M mode).
*
* This is a simplified model with an Undulator, mirrors, a double crystal 
* monochromator, a sample stage and a detector.
*
* %Example: E0=12.65 sample="Mo.lau" Detector: Eiger9M_I=3e+11
* %Example: E0=12.65 Detector: Eiger9M_I=1.5e+15
*
* %Parameters
* E0:    [keV] Energy selected at the Undulator.
* hfm_radius: [m] horizontally focusing mirror radius
* vfm_radius: [m] vertically focusing mirror radius
* mirror_grazing_angle: [deg] Tilt angle of the mirrors.
* sample:[str] Sample structure file, LAU/CIF format.
* rotX:  [deg] Sample rotation around X
* rotY:  [deg] Sample rotation around Y
* rotZ:  [deg] Sample rotation around Z
* 
* %Link
* https://www.synchrotron-soleil.fr/en/beamlines/proxima-2a
*
* %End
*******************************************************************************/

DEFINE INSTRUMENT SOLEIL_PX2a(
  E0=12.65, hfm_radius=495, vfm_radius=859,
  mirror_grazing_angle=4e-3,
  string sample="adrenaline.lau",
  rotX=0, rotY=0, rotZ=0)

DECLARE
%{
    double calculated_angle;
%}

USERVARS %{
    int    flag_hfm;
    int    flag_vfm;
%}

INITIALIZE
%{
  double arg=  12398.42*sqrt(3)/(2*5.4309*E0*1e3);
  if (fabs(arg) > 1)
    exit(fprintf(stderr, "ERROR: Monochromator can not reach this energy (arg=%g > 1)\n",
      arg));
  calculated_angle = RAD2DEG*asin(arg);
  
%}

TRACE

COMPONENT Origin = Progress_bar()
AT (0,0,0) ABSOLUTE

// Undulator U24
COMPONENT undulator = Undulator(
    E0=E0, 
    dE=.1, 
    Ee=2.75, 
    dEe=0.001, 
    Ie=0.5, 
    K=1.788, 
    Nper=80, 
    lu=2.4e-2, 
    sigey=9.8e-6, 
    sigex=219.1e-6, 
    sigepx=31.6e-6, 
    sigepy=3.7e-6, 
    dist=29.5, 
    E1st=12.400)
AT (0, 0, 0) RELATIVE PREVIOUS



// Channel_cut Si(111) ---------------------------------------------------------
// gap 6 mm
COMPONENT bragg_crystal_location = Arm()
AT (0,0,29.5) RELATIVE PREVIOUS

COMPONENT bragg_crystal = Bragg_crystal(
    crystal_type=2)
AT (0, 0, 0) RELATIVE PREVIOUS
ROTATED (-calculated_angle, 0, 0) RELATIVE PREVIOUS

COMPONENT arm = Arm()
AT (0, 0, 0) RELATIVE PREVIOUS
ROTATED (-calculated_angle, 0, 0) RELATIVE PREVIOUS

COMPONENT bragg_crystal_two = Bragg_crystal(
    crystal_type=2)
AT (0, 0.006, calculated_angle ? 0.006/tan(calculated_angle*DEG2RAD) : 0) RELATIVE bragg_crystal
ROTATED (calculated_angle, 0, 0) RELATIVE PREVIOUS

COMPONENT arm_two = Arm()
AT (0, 0, 0) RELATIVE bragg_crystal_two
ROTATED (calculated_angle, 0, 0) RELATIVE bragg_crystal_two

COMPONENT bragg_crystal_out = E_monitor(Emin=E0-.1, Emax=E0+.1, nE=512,
  xwidth=0.1, yheight=0.1)
AT(0,0,0.2) RELATIVE PREVIOUS


// horizontal pre-focusing curved mirror (XZ -> YZ plane) ----------------------
COMPONENT hpm_location = Arm()
AT (0,0,32.1-29.5-0.05) RELATIVE arm_two

COMPONENT hpm_in_yz_plane = Arm()
AT (0,0,0) RELATIVE hpm_location
ROTATED (0,0,90) RELATIVE hpm_location

COMPONENT hpm = Mirror_toroid(
  coating   = "Ir.dat", //This needs to be Rh.dat, will need to generate the file with xraydb
  zdepth   = 150e-3,
  xwidth   = 15e-3,
  radius   = 495,
  radius_o = 1000)
AT (0,0,0) RELATIVE hpm_in_yz_plane
ROTATED (mirror_grazing_angle, 0, 0) RELATIVE hpm_in_yz_plane

COMPONENT hpm_takeoff = Arm()
AT (0,0,0) RELATIVE hpm_location
ROTATED (0, 2*mirror_grazing_angle, 0) RELATIVE hpm_location

// KB pair ---------------------------------------------------------------------
// could use Mirror_elliptic
// incidence angle 4 mrad

// KB 1st mirror (XZ plane) at 1.6m from sample
// must be shifted by -2 mm  on Y else beam flies underneath the mirror.
COMPONENT vfm_location = Monitor_nD(xwidth=0.01, yheight=0.01, options="x y", bins=100)
AT (0,0,33.9-32.1) RELATIVE hpm_takeoff

COMPONENT vfm_in_xz_plane = Arm()
AT (0,0,0) RELATIVE vfm_location
ROTATED(0,0,-90) RELATIVE vfm_location // YZ -> XZ

COMPONENT vfm = Mirror_curved(
  coating="Rh.txt",
  length=450e-3,
  width=0.1,
  radius=vfm_radius)
AT (0,0,0) RELATIVE vfm_location
ROTATED(0,-mirror_grazing_angle,0) RELATIVE vfm_in_xz_plane
EXTEND %{
  flag_vfm=SCATTERED;
%}

COMPONENT vfm_takeoff = COPY(vfm_location)
AT (0,0,0) RELATIVE vfm_in_xz_plane
ROTATED (-2*mirror_grazing_angle, 0, 0) RELATIVE vfm_location

// KB 2nd mirror (YZ) at 1m from sample, shift height=4.8 mm 
COMPONENT hfm_location = COPY(vfm_location)
AT (0,0,34.5-33.9) RELATIVE vfm_takeoff

// 859 m tangential; sagital > 1 km, in YZ plane
COMPONENT hfm = Mirror_curved(
  coating="Rh.txt",
  length=450e-3,
  width=0.1,
  radius=hfm_radius)
AT (0,0,0) RELATIVE hfm_location
ROTATED (0,-mirror_grazing_angle,0) RELATIVE hfm_location
EXTEND %{
  flag_hfm=SCATTERED;
%}

COMPONENT hfm_takeoff = COPY(vfm_location)
AT (0,0,0) RELATIVE hfm_location
ROTATED (0,-2*mirror_grazing_angle,0) RELATIVE hfm_location

// Sample ----------------------------------------------------------------------
// we centre the beam after the KB.
COMPONENT sample_stage = Arm()
AT (1e-3,-1.1e-3,1) RELATIVE hfm_takeoff
EXTEND %{
  if (!flag_hfm || !flag_vfm) ABSORB;
%}

COMPONENT sample_monitor = Monitor_nD(
  xwidth = 0.01, yheight = 0.01,
  options = "x y", bins=100)
  AT (0, 0, 0) RELATIVE sample_stage

SPLIT COMPONENT sample = Single_crystal(reflections=sample, material_datafile="NULL", 
  radius = .5e-4, yheight = 5e-3, p_transmit = 0, mosaic=0.1)
  AT (0, 0, 0) RELATIVE sample_stage
  ROTATED (rotX,rotY,rotZ) RELATIVE sample_stage
EXTEND %{
  if (!SCATTERED) ABSORB;
%}

COMPONENT psd4pi = PSD_monitor_4PI(
    nx = 180, ny = 180, filename = "psd4pi", radius = 0.1, restore_xray = 1)
AT (0, 0, 0) RELATIVE sample

// Detector
COMPONENT Eiger9M = PSD_monitor(
  nx=3108, ny=3262,
  xwidth = 233.1e-3,
  yheight= 244.7e-3,
  filename="Eiger9M.dat"
)
AT (0,0,0.12) RELATIVE sample_stage

END
