diff --git a/mcxtrace-comps/examples/SOLEIL/SOLEIL_NANOSCOPIUM/SOLEIL_NANOSCOPIUM.instr b/mcxtrace-comps/examples/SOLEIL/SOLEIL_NANOSCOPIUM/SOLEIL_NANOSCOPIUM.instr new file mode 100644 index 0000000000..80a64ba631 --- /dev/null +++ b/mcxtrace-comps/examples/SOLEIL/SOLEIL_NANOSCOPIUM/SOLEIL_NANOSCOPIUM.instr @@ -0,0 +1,442 @@ +/******************************************************************************* +* Instrument: SOLEIL_NANOSCOPIUM +* +* %Identification +* Written by: C.Gaudry +* Date: 10/2026 +* Origin: Synchrotron SOLEIL +* %INSTRUMENT_SITE: SOLEIL +* +* The NANOSCOPIUM tomography beam-line at Synchrotron SOLEIL. +* +* %Description +* The beamline NANOSCOPIUM +* works at photon energies between 5 and 50 keV. It is dedicated to full-field +* radiography and tomography in absorption and phase contrast, with pixel sizes +* from 20 nm to 20 µm. +* +* List of beamline elements. Distances are given from the center of the undulator. +* +* Position (m) | Element +* -------------|--------------------------------------------- +* 0 | Undulator (source) +* 18.109 | Primary slits +* 22.655 | Mirror M1 (curved) : horizontal deviation, vertical focus +* 24.471 | Mirror M2 (curved) : horizontal deviation, horizontal focus +* 75.758 | Secondary slits +* 77.224 | Monochromator (DCM) +* 82.064 | Slits Secondary source +* 148.893 | Slits JJ XRay 1 (entry Nanoprobe 1) (doesn't work) +* 150.721 | Nano-probe 1 (doesn't work) +* 154.353 | Slits JJ XRay 2 (entry Nanoprobe 2) +* 154.856 | Mirror KB1 (elliptic) : vertical focus +* 154.961 | Mirror KB2 (elliptic) : horizontal focus +* 155.140 | Nano-probe 2 +* +* %Example: NANO_E0=11 Detector: NANO_e_dcm_out_I=4.09492e+10 +* +* %Parameters +* NANO_E0 [keV] Energy selected at the Undulator. +* NANO_dE [keV] Energy spread at the Undulator. +* NANO_Emono [keV] Energy to be selected by the monochromator, or E0 when unset. +* NANO_coating_m2 [1] 2 stripes on M2 : Rh (coated : 1) or Si (uncoated : 0) +* NANO_angle_m1_m2 [rad] Incidence angle on M1 and M2 mirrors +* NANO_angle_kb1 [rad] Incidence angle on the first KB mirror (vertical focus) +* NANO_angle_kb2 [rad] Incidence angle on the second KB mirror (horizontal focus) +* +* %End +*******************************************************************************/ +DEFINE INSTRUMENT SOLEIL_NANOSCOPIUM(NANO_E0=11, NANO_dE=1, NANO_Emono=0, int NANO_coating_m2=1, NANO_angle_m1_m2=2.5e-3, NANO_angle_kb1=3e-3, NANO_angle_kb2=2.5e-3) + + +DECLARE +%{ + double NANO_angle_dcm; // incident angle on monochromator -> depends on energy wanted + double NANO_delta_dcm; // translation of the second crystal according to the energy selected + char NANO_material_coating_m2[20]; + double NANO_E1_target; // First harmonic coresponding to the energy selected + // double f_fresnel; // focal length of the fresnel zone plate (depends on energy selected) +%} + +INITIALIZE +%{ + { + // COMPUTE THE BRAGG ANGLE ------------------------------------------------------------- + if (NANO_Emono==0) NANO_Emono=NANO_E0; + + // check if NANO_Emono is accessible and calculate the coresponding Bragg angle (if possible) + if (NANO_E0-NANO_dE < NANO_Emono && NANO_Emono < NANO_E0+NANO_dE) { + + double arg= (12.39842*sqrt(3)) / (2*5.4309*NANO_Emono); + if (fabs(arg) > 1) + exit(printf("%s: ERROR: Monochromator can not reach this energy.\n", NAME_INSTRUMENT)); + NANO_angle_dcm = RAD2DEG*asin(arg); + NANO_delta_dcm = 0.02 / tan(2.0*DEG2RAD*NANO_angle_dcm); + } else { + exit(printf("%s: ERROR: Monochromator energy is outside the Undulator bandwidth.\n", NAME_INSTRUMENT)); + } + + // COMPUTE THE 1st HARMONIC FOR UNDULATOR --------------------------------------------- + // search the largest odd harmonic so that K is valid (K>0 and KK_max ) && harmonic < 51) { // check if K is valid for the undulator + NANO_E1_target = NANO_E0 / harmonic; + double K2 = 2.0*( (0.95*Ee*Ee)/(NANO_E1_target*lambda_u) - 1); + + if (K2>=0) K = sqrt(K2); + harmonic += 2; + } + harmonic -=2; + if (harmonic==51) {printf("Harmonic = %d, has stopped. NANO_E1_target = %g and K = %g \n", harmonic,NANO_E1_target, K);} + printf("With the selected energy %g keV, the calculated first harmonic is : harmonic %d = %g keV. \n", NANO_E0, harmonic, NANO_E1_target); + printf("The corresponding K is : %g\n", K); + + // SET STRIPE USED IN M2 MIRROR -------------------------------------------------------- + if (NANO_coating_m2==0) { + // uncoated surface_ + sprintf(NANO_material_coating_m2,"Si.txt"); + } else if (NANO_coating_m2==1) { + // coated surface + sprintf(NANO_material_coating_m2,"Rh.txt"); + } else { + exit(printf("%s: ERROR: Invalid coating for M2, must be 0 (uncoated) or 1 (coated).\n", NAME_INSTRUMENT)); + } + /* + // COMPUTE FOCAL LENGTH OF ZONE PLATE + // the beam is approximately 100micrometers extended while entering in the zone plate -> diameter will be 100e-6m. We want a 50nm beam after the zone plate (Rayleigh criterion) delta_r_N = 40nm. + f_fresnel = (100e-6 * 40e-9 * NANO_E0) / 12.39842; + */ + } +%} + +TRACE + +REMOVABLE COMPONENT origin = Progress_bar() +AT (0, 0, 0) RELATIVE ABSOLUTE + +// -------------------------------- Source + +// values are found in GMI +// minimum gap = 5.5mm + +COMPONENT NANO_source=Undulator( + E0=NANO_E0, dE=NANO_dE, Ee=2.75, dEe=0.001, Ie=0.5, + E1st=NANO_E1_target, Nper=106, lu=1.8e-2, + sigex=258.6e-6, sigey=8.8e-6, sigepx=31.2e-6, sigepy=3.5e-6, + dist=22.655, focus_xw=100e-6, focus_yh=100e-6, phase=0, randomphase=0) +AT (0, 0, 0) RELATIVE PREVIOUS + +COMPONENT NANO_e_monitor_source = E_monitor( + filename="e_monitor_source.dat", + xwidth=0.1, + yheight=0.1, + Emin=NANO_E0-NANO_dE, + Emax=NANO_E0+NANO_dE, + nE=500, + restore_xray=1) +AT (0, 0, 0) RELATIVE PREVIOUS + +COMPONENT NANO_psd_source=PSD_monitor_coh( + filename="psd_source.dat", + xwidth=0.05, + yheight=0.05, + centering=0, + restore_xray=1) +AT (0,0,0) RELATIVE PREVIOUS + +// ------------------------------------ Primary slits +COMPONENT NANO_slit_1 = Slit( + xwidth=0.0008, + yheight=0.0008) +AT (0,0,18.109) RELATIVE PREVIOUS + +// ------------------------------------ Mirror M1 (C03) + +// distance to source : 22655mm -> distance to previous : 22655-18.109 = 4.546m +// curvature in xy plane -> 90° rotation is needed -> width and length are exchanged +COMPONENT NANO_m1_in=Arm() +AT (0, 0, 4.546) RELATIVE PREVIOUS + +// COMPONENT NANO_psd_m1_in=PSD_monitor( +// filename="psd_m1_in.dat", +// xwidth=0.002, +// yheight=0.002) +// AT (0,0,0) RELATIVE PREVIOUS + +COMPONENT NANO_m1_roll=Arm() +AT (0,0,0) RELATIVE PREVIOUS +ROTATED (-90,0,0) RELATIVE PREVIOUS + +// Distance to source = 22.625m - distance to image = 59.409m => radius = 10.923m +// in documentation, R_tangential > 10km and R_sagittal=81.5mm +COMPONENT NANO_mirror_m1 = Mirror_curved( + radius=-82e-3, + zdepth=0.029, + yheight=0.351, + coating="Rh.txt") +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, 0, -NANO_angle_m1_m2*RAD2DEG) RELATIVE PREVIOUS +EXTEND %{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_beam_deviation=Arm() +AT (0,0,0) RELATIVE NANO_m1_in +ROTATED (0,-2.0*NANO_angle_m1_m2*RAD2DEG,0) RELATIVE NANO_m1_in + +// ---------------------------------- Mirror M2 (C04) + +COMPONENT NANO_m2_in=Arm() +AT (0,0,1.816) RELATIVE PREVIOUS + +// COMPONENT NANO_psd_m2_in = PSD_monitor( +// filename="psd_m2_in.dat", +// xwidth=0.005, +// yheight=0.005) +// AT (0, 0, 0) RELATIVE PREVIOUS + +// M2 should be placed at 1.816 from M1 +COMPONENT NANO_mirror_m2 = Mirror_curved( + radius=-13739, + yheight=0.029, + zdepth=0.351, + coating=NANO_material_coating_m2) +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, -NANO_angle_m1_m2*RAD2DEG, 0) RELATIVE PREVIOUS +EXTEND %{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_mirror_m2_out = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, -NANO_angle_m1_m2*RAD2DEG, 0) RELATIVE PREVIOUS + +// ----------------------------------- Secondary slits (C05) +// xwidth and yheight TODO +COMPONENT NANO_slit_2 = Slit( + xwidth=2e-3, + yheight=5e-4) +AT (0,0,51.287) RELATIVE PREVIOUS + +// ---------------------------------- Monochromator (C06) + +// dcm first crystal at 52.753m from M2 -> at 1.466 from secondary slits +COMPONENT NANO_dcm_in=Arm() +AT (0,0,1.466) RELATIVE PREVIOUS + +COMPONENT NANO_PSD_dcm_in=PSD_monitor( + filename="psd_dcm_in.dat", + xwidth=3e-3, + yheight=10e-4) +AT (0,0,0) RELATIVE PREVIOUS + +// the bragg crystal is in the YZ plane -> 90° rotation is needed +COMPONENT NANO_bragg_roll=Arm() +AT (0,0,0) RELATIVE PREVIOUS +ROTATED (0,0,90) RELATIVE PREVIOUS + +COMPONENT NANO_bragg_crystal_1 = Bragg_crystal( + length=0.05, + width=0.02, + material = "Si.txt", + h = 1, + k = 1, + l = 1, + crystal_type = 2) +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (-NANO_angle_dcm, 0, 0) RELATIVE PREVIOUS +EXTEND %{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_dcm2_rot = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (-NANO_angle_dcm, 0, 0) RELATIVE PREVIOUS + +// the distance between the two crystals is -h along the "absolute" X-axis where h is fixed at 20mm +COMPONENT NANO_dcm_transl=Arm() +AT (-0.02,0,NANO_delta_dcm) RELATIVE NANO_dcm_in + +// the second bragg crystal is in the YZ plane -> 90° rotation +COMPONENT NANO_bragg_crystal_2 = Bragg_crystal( + length=0.115, + width=0.02, + material = "Si.txt", + h = 1, + k = 1, + l = 1, + crystal_type = 2) +AT (0, 0, 0) RELATIVE NANO_dcm_transl +ROTATED (NANO_angle_dcm, 0, 0) RELATIVE NANO_dcm2_rot +EXTEND %{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_bragg2_out = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (NANO_angle_dcm, 0, 0) RELATIVE PREVIOUS + +COMPONENT NANO_dcm_out = Arm() +AT (0,0,0) RELATIVE PREVIOUS +ROTATED (0,0,0) RELATIVE NANO_dcm_in + +COMPONENT NANO_e_dcm_out = E_monitor( + filename="e_dcm_out.dat", + xwidth=0.1, + yheight=0.1, + Emin=NANO_E0-NANO_dE, + Emax=NANO_E0+NANO_dE, + nE=500, + restore_xray=1) +AT (0, 0, 1) RELATIVE PREVIOUS +ROTATED (0,0,0) RELATIVE PREVIOUS + +// ------------------------------------------ Slits secondary source (C08) +COMPONENT NANO_secondary_source_slits=Arm() +AT (0,0,4.84) RELATIVE NANO_dcm_out + +COMPONENT NANO_psd_ss_in=PSD_monitor( + filename="psd_ss_in.dat", + xwidth=0.002, + yheight=0.002) +AT (0,0,0) RELATIVE PREVIOUS + +// xwidth and yheight OK (opticaldesign_jsr_2015_0.pdf) +COMPONENT NANO_slit_3 = Slit( + xwidth=50e-6, + yheight=50e-6) +AT (0,0,0) RELATIVE PREVIOUS + +COMPONENT NANO_psd_ss_out=PSD_monitor( + filename="psd_ss_out.dat", + xwidth=1e-3, + yheight=1e-3) +AT (0,0,5) RELATIVE PREVIOUS + +/* +// ----------------------------------------- Slits entry Nano-probe 1 (CX2) +// slits are at 71669mm from dcm +COMPONENT NANO_jjxray1_slits=Arm() +AT (0,0,66.829) RELATIVE secondary_source_slits + +COMPONENT NANO_psd_jjxray1_in=PSD_monitor( + xwidth=0.002, + yheight=0.002) +AT (0,0,0) RELATIVE PREVIOUS + +// xwidth and yheight TODO +COMPONENT NANO_slit_4 = Slit( + xwidth=300e-6, + yheight=300e-6) +AT (0,0,0) RELATIVE PREVIOUS + +// ---------------------------------------- Nano-probe 1 (CX2) +COMPONENT NANO_focalisation=Arm() +AT (0,0,1.825) RELATIVE jjxray1_slits +*/ +// central stop +/* +COMPONENT NANO_centralStop=Beamstop( + radius=20e-6) +AT (0,0,0) RELATIVE PREVIOUS +*/ +/* +COMPONENT NANO_psd_fzp_in=PSD_monitor( + xwidth=500e-6, + yheight=500e-6) +AT (0,0,0) RELATIVE PREVIOUS + +// Fresnel Zone Plate +COMPONENT NANO_zoneplate=ZonePlate( + radius=150e-6, + L=0.155, + lambda0=12.3984/16.0, + focus_xw=1e-6, + focus_yh=1e-6, + dist=0.1694) +AT (0,0,0) RELATIVE PREVIOUS +*/ +// OSA +/* +COMPONENT NANO_OSA=Slit( + radius=25e-6) +AT (0,0,0.13) RELATIVE zoneplate +*/ +/* +COMPONENT NANO_psd_nanoprobe_1=PSD_monitor_coh( + nx=250, + ny=250, + xwidth=1e-6, + yheight=1e-6, + centering=1, + restore_xray=1) +AT (0,0,0.155) RELATIVE zoneplate +*/ +// ---------------------------------------- jjxray2 slits : entry Nanoprobe2 (CX3) + +COMPONENT NANO_jjxray2_slits=Arm() +AT (0,0,72.289) RELATIVE NANO_secondary_source_slits + +// xwidth and yheight TODO +COMPONENT NANO_slit_5 = Slit( + xwidth=50e-6, + yheight=50e-6) +AT (0,0,0) RELATIVE PREVIOUS + +// -------------------------------------- Mirrors KB (CX3) +COMPONENT NANO_kb_in = Arm() +AT (0, 0, 0.503) RELATIVE PREVIOUS +ROTATED (0, 0, 90) RELATIVE PREVIOUS + +COMPONENT NANO_kb_1 = Mirror_curved( + radius=189.259, + length=0.1, + width=0.04) +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, RAD2DEG*NANO_angle_kb1, 0) RELATIVE PREVIOUS +EXTEND +%{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_kb_beam_deviation = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, RAD2DEG*NANO_angle_kb1, 0) RELATIVE PREVIOUS + +COMPONENT NANO_kb1_out = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, 0, -90) RELATIVE PREVIOUS + +COMPONENT NANO_kb2 = Mirror_curved( + radius=-143.645, + length=0.1, + width=0.04) +AT (0, 0, 0.105) RELATIVE PREVIOUS +ROTATED (0, -RAD2DEG*NANO_angle_kb2, 0) RELATIVE PREVIOUS +EXTEND +%{ + if (!SCATTERED) ABSORB; +%} + +COMPONENT NANO_kb_out = Arm() +AT (0, 0, 0) RELATIVE PREVIOUS +ROTATED (0, -RAD2DEG*NANO_angle_kb2, 0) RELATIVE PREVIOUS + +COMPONENT NANO_slit=Slit( + xwidth=20e-6, + yheight=20e-6) +AT (0,0,0.18*0.5) RELATIVE NANO_kb_out + +COMPONENT NANO_psd_sample_stage = PSD_monitor( + xwidth=0.000005, + yheight=0.000005, + restore_xray=1 + ) +AT (0, 0, 0.18) RELATIVE NANO_kb_out + +END