|
18 | 18 | * This component is a more complex implementation of Monochromator_bent. |
19 | 19 | * This component only differs in the fact that it allows and forces the user |
20 | 20 | * to set every single parameter for every single crystal in the crystal array. |
| 21 | +* An exception to this rule is the plane of reflection, for which one can |
| 22 | +* choose a single plane of reflection, and that will work for all crystals. |
21 | 23 | * |
22 | 24 | * |
23 | 25 | * %Parameters |
|
27 | 29 | * xthickness: [m] Thickness of each crystal without bending. |
28 | 30 | * radius_x: [m] Radius of the circle the monochromator bends on in the plane. Can be negative. |
29 | 31 | * radius_y: [m] Radius of the (very large) circle the monochromator bends on as a side effect of the horizontal bending. The code assumes that it is so small that it does not affect the points of intersection appreciatively of the crystal. |
30 | | -* plane_of_reflection: ["Si400"] The plane of reflection from the material. The list of possible reflections can be seen in the source code. |
| 32 | +* plane_of_reflection: [string] The plane of reflection from the material. The list of possible reflections can be seen in the source code. Each plane must be separated by a ";", like "Si400;Si111". |
31 | 33 | * angle_to_cut_horizontal: [degrees] Angle between cut and normal of crystal slab, horizontally |
32 | 34 | * mosaicity: [arcmin] Gaussian mosaicity of the crystal. Always the horizontal mosaicity |
33 | 35 | * mosaic_anisotropy: [1] Anisotropy of the mosaicity, changes vertical mosaicity to be mosaic_anisotropy*mosaicity |
34 | | -* n_crystals: [#] Number of crystals in your array. |
35 | | -* domainthickness: [mu-m] Thickness of the crystal domains. |
36 | | -* temperature: [K]Temperature of the monochromator in Kelvin. |
37 | | -* optimize: [ ] Flag to tell if the component should optimize for reflections or not. |
| 36 | +* n_crystals: [1] Number of crystals in your array. |
| 37 | +* domainthickness: [μm] Thickness of the crystal domains. |
| 38 | +* temperature: [K] Temperature of the monochromator in Kelvin. |
| 39 | +* optimize: [1] Flag to tell if the component should optimize for reflections or not. |
38 | 40 | * x_pos: [vector] x-Position of each crystal |
39 | 41 | * y_pos: [vector] y-Position of each crystal |
40 | 42 | * z_pos: [vector] z-Position of each crystal |
41 | 43 | * x_rot: [vector] Rotation around x-axis for each crystal |
42 | 44 | * y_rot: [vector] Rotation around y-axis for each crystal |
43 | 45 | * z_rot: [vector] Rotation around z-axis for each crystal NOTE: Rotations happen around x, then y, then z. |
44 | | -* verbose: [ ] Verbosity of the monochromator. Used for debugging. |
45 | | -* draw_as_rectangles: [ ] Draw the monochromators as boxes. DOES NOT WORK WHEN USING _rot parameters. |
| 46 | +* verbose: [1] Verbosity of the monochromator. Used for debugging. |
| 47 | +* draw_as_rectangles: [1] Draw the monochromators as boxes. DOES NOT WORK WHEN USING _rot parameters. |
46 | 48 | * |
47 | 49 | * %L |
48 | 50 | * <a href="https://doi.org/10.1016/j.nima.2004.04.197">Jan Šaroun NIM A Volume 529, Issue 1-3 (2004), pp162-165</a> |
| 51 | +* <a href="https://doi.org/10.3390/qubs10010006">Christensen, D.L.; Cabeza, S.; Pirling, T.; Lefmann, K.; Šaroun, J. Simulating Neutron Diffraction from Deformed Mosaic Crystals in McStas. Quantum Beam Sci. 2026, 10, 6. https://doi.org/10.3390/qubs10010006</a> |
49 | 52 | * |
50 | 53 | * %E |
51 | 54 | *******************************************************************************/ |
@@ -75,7 +78,30 @@ SETTING PARAMETERS (vector zwidth=NULL, |
75 | 78 | NOACC |
76 | 79 | // The component is currently "NOACC" only, there are thread race-conditions on GPU |
77 | 80 |
|
78 | | -SHARE INHERIT Monochromator_bent |
| 81 | +SHARE INHERIT Monochromator_bent EXTEND %{ |
| 82 | +char *repeat_with_semicolon(const char *src, int n) { |
| 83 | + size_t len = strlen(src); |
| 84 | + size_t total = n * len + (n - 1) + 1; // repetitions + semicolons + null terminator |
| 85 | + |
| 86 | + char *result = malloc(total); |
| 87 | + if (!result) return NULL; |
| 88 | + |
| 89 | + char *p = result; |
| 90 | + |
| 91 | + for (int i = 0; i < n; i++) { |
| 92 | + memcpy(p, src, len); |
| 93 | + p += len; |
| 94 | + |
| 95 | + if (i < n - 1) { |
| 96 | + *p = ';'; |
| 97 | + p++; |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + *p = '\0'; |
| 102 | + return result; |
| 103 | +} |
| 104 | +%} |
79 | 105 | DECLARE |
80 | 106 | %{ |
81 | 107 | int counter; |
@@ -106,19 +132,39 @@ INITIALIZE |
106 | 132 | mono_arr.verbosity = verbose; // [#] |
107 | 133 |
|
108 | 134 | // Separate the string into individual crystals |
109 | | - int MAX_TOKENS = 6 * n_crystals; |
| 135 | + // If no semicolon is present, parse the string as a single plane of reflection |
| 136 | + // and apply that to all crystals |
110 | 137 |
|
111 | | - char** planes = malloc (n_crystals * sizeof (char*)); |
112 | | - if (planes == NULL) { |
113 | | - exit (fprintf (stderr, "Error: memory allocation failed for planes\n")); |
| 138 | + char* input_string = NULL; |
| 139 | + |
| 140 | + if (strchr (plane_of_reflection, ';') == NULL && n_crystals > 1) { |
| 141 | + // Apply the same plane to all crystals |
| 142 | + input_string = repeat_with_semicolon (plane_of_reflection, n_crystals); |
| 143 | + } else { |
| 144 | + // Use the original string |
| 145 | + input_string = strdup (plane_of_reflection); |
114 | 146 | } |
115 | | - int token_count = 0; |
| 147 | + |
| 148 | + if (!input_string) { |
| 149 | + fprintf (stderr, "Error: memory allocation failed\n"); |
| 150 | + exit (-1); |
| 151 | + } |
| 152 | + |
116 | 153 | // Remove trailing newline, if any |
117 | | - plane_of_reflection[strcspn (plane_of_reflection, "\n")] = '\0'; |
| 154 | + input_string[strcspn (input_string, "\n")] = '\0'; |
| 155 | + |
| 156 | + // Allocate array for tokens |
| 157 | + char** planes = malloc (n_crystals * sizeof (char*)); |
| 158 | + if (!planes) { |
| 159 | + fprintf (stderr, "Error: memory allocation failed for planes\n"); |
| 160 | + free (input_string); |
| 161 | + exit (-1); |
| 162 | + } |
118 | 163 |
|
119 | 164 | // Tokenize the string using ';' as delimiter |
120 | | - char* plane = strtok (plane_of_reflection, ";"); |
121 | | - while (plane != NULL && token_count < MAX_TOKENS) { |
| 165 | + int token_count = 0; |
| 166 | + char* plane = strtok (input_string, ";"); |
| 167 | + while (plane != NULL && token_count < n_crystals) { |
122 | 168 | planes[token_count++] = plane; |
123 | 169 | plane = strtok (NULL, ";"); |
124 | 170 | } |
@@ -227,6 +273,8 @@ INITIALIZE |
227 | 273 | mono_arr.crystal[i].lattice_spacing_gradient_field[2][2] = -cos (chi) * tau_size_zero * curvature; |
228 | 274 | } |
229 | 275 | free (planes); |
| 276 | + free (input_string); |
| 277 | + |
230 | 278 | // TODO: This is very gpu unfriendly. Should be changed to depend on OPENACC usage |
231 | 279 | // Initialize neutron structs values |
232 | 280 | neutron.beta = (double*)calloc (n_crystals, sizeof (double)); |
|
0 commit comments