Skip to content

Commit 0990a4e

Browse files
Further bug fixes of interface system, now in good state where
complex examples run without loosing any rays. Template_surface and Mirror_surface do the same thing, the template is available for a developer to start coding a surface process without overwriting any other code. It contains help with getting started.
1 parent 30ec823 commit 0990a4e

File tree

4 files changed

+293
-51
lines changed

4 files changed

+293
-51
lines changed

mcstas-comps/share/union-lib.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum process {
3838

3939
enum surface {
4040
Mirror,
41-
SurfaceTemplate
41+
SurfaceTemplate
4242
};
4343

4444
enum in_or_out {
@@ -411,8 +411,8 @@ struct pointer_to_1d_int_list focus_array_indices; // Add 1D integer array with
411411

412412

413413
// intersect_function takes position/velocity of ray and parameters, returns time list
414-
int (*intersect_function)(double*, double*, double*, double*, int*, int*,double*,double*,struct geometry_struct*);
415-
// t_array, nx array, ny array, nz array, surface_index array, n arary, r ,v
414+
int (*intersect_function)(double*, double*, double*, double*, int*, int*, double*, double*, struct geometry_struct*);
415+
// t_array, nx array, ny array, nz array, surface_index array, n arary, r ,v
416416

417417
// within_function that checks if the ray origin is within this volume
418418
int (*within_function)(Coords,struct geometry_struct*);
@@ -518,7 +518,7 @@ int (*scattering_function)(double*,double*,double*,union data_transfer_union,str
518518

519519
union surface_data_transfer_union
520520
{
521-
//struct Mirror_surface_storage_struct *pointer_to_a_Mirror_surface_storage_struct;
521+
struct Mirror_surface_storage_struct *pointer_to_a_Mirror_surface_storage_struct;
522522
struct Template_surface_storage_struct *pointer_to_a_Template_surface_storage_struct;
523523
};
524524

@@ -2021,15 +2021,15 @@ struct lines_to_draw draw_line_with_highest_priority(Coords position1,Coords pos
20212021
int geometry_output;
20222022

20232023
// Todo: switch to nicer intersect function call
2024-
double double_dummy;
2025-
int int_dummy;
2024+
double double_dummy[2];
2025+
int int_dummy[2];
20262026

20272027

20282028
// Find intersections
20292029
for (volume_index = 1;volume_index < number_of_volumes; volume_index++) {
20302030
if (volume_index != N) {
2031-
geometry_output = Geometries[volume_index]->intersect_function(temp_intersection, &double_dummy, &double_dummy, &double_dummy, &int_dummy,
2032-
&number_of_solutions,r1,direction,Geometries[volume_index]);
2031+
geometry_output = Geometries[volume_index]->intersect_function(temp_intersection, double_dummy, double_dummy, double_dummy, int_dummy,
2032+
&number_of_solutions, r1, direction, Geometries[volume_index]);
20332033
// printf("No solutions for intersection (Volume %d) with %d \n",N,volume_index);
20342034
for (iterate=0;iterate<number_of_solutions;iterate++) {
20352035
// print_1d_double_list(intersection_list,"intersection_list");
@@ -2794,7 +2794,8 @@ int sample_box_intersect_simple(double *t, double *nx, double *ny, double *nz, i
27942794
int output;
27952795
// Run McStas built in box intersect funtion (box centered around origin)
27962796
if ((output = box_intersect(&t[0],&t[1],rotated_coordinates.x,rotated_coordinates.y,rotated_coordinates.z,rotated_velocity.x,rotated_velocity.y,rotated_velocity.z,width,height,depth)) == 0) {
2797-
*num_solutions = 0;t[0]=-1;t[1]=-1;}
2797+
*num_solutions = 0;t[0]=-1;t[1]=-1;
2798+
}
27982799
else if (t[1] != 0) *num_solutions = 2;
27992800
else {*num_solutions = 1;t[1]=-1;} // t[2] is a memory error!
28002801

@@ -2814,7 +2815,18 @@ int sample_box_intersect_simple(double *t, double *nx, double *ny, double *nz, i
28142815
z = rotated_coordinates.z + dt*rotated_velocity.z;
28152816

28162817
// determine hit face: difference to plane is closest to 0 (in box coordinate system)
2817-
normal_vector_rotated = coords_set(trunc(2.002*x/width), trunc(2.002*y/height), trunc(2.002*z/depth));
2818+
// A deviation of 0 means its on that surface, due to finite accuracy it will never be exact, so the closest is chosen
2819+
double x_deviation = fabs(fabs(x/width) - 0.5);
2820+
double y_deviation = fabs(fabs(y/height) - 0.5);
2821+
double z_deviation = fabs(fabs(z/depth) - 0.5);
2822+
2823+
if (x_deviation <= y_deviation && x_deviation <= z_deviation) {
2824+
normal_vector_rotated = coords_set(x > 0 ? 1.0 : -1.0, 0.0, 0.0);
2825+
} else if (y_deviation <= x_deviation && y_deviation <= z_deviation) {
2826+
normal_vector_rotated = coords_set(0.0, y > 0 ? 1.0 : -1.0, 0.0);
2827+
} else {
2828+
normal_vector_rotated = coords_set(0.0, 0.0, z > 0 ? 1.0 : -1.0);
2829+
}
28182830

28192831
// Set surface index
28202832
if (normal_vector_rotated.z < -0.5)
@@ -2843,6 +2855,8 @@ int sample_box_intersect_simple(double *t, double *nx, double *ny, double *nz, i
28432855
nx[index] = normal_vector.x;
28442856
ny[index] = normal_vector.y;
28452857
nz[index] = normal_vector.z;
2858+
2859+
NORM(nx[index], ny[index], nz[index]);
28462860
}
28472861

28482862
return output;
@@ -3934,10 +3948,10 @@ int existence_of_intersection(Coords point1, Coords point2, struct geometry_stru
39343948
vector_between_v[0] = vector_between.x;vector_between_v[1] = vector_between.y;vector_between_v[2] = vector_between.z;
39353949

39363950
// todo: Switch to nicer intersect call
3937-
double dummy_double;
3938-
int dummy_int;
3951+
double dummy_double[2];
3952+
int dummy_int[2];
39393953

3940-
geometry->intersect_function(temp_solution, &dummy_double, &dummy_double, &dummy_double, &dummy_int, &number_of_solutions,start_point,vector_between_v,geometry);
3954+
geometry->intersect_function(temp_solution, dummy_double, dummy_double, dummy_double, dummy_int, &number_of_solutions, start_point, vector_between_v, geometry);
39413955
if (number_of_solutions > 0) {
39423956
if (temp_solution[0] > 0 && temp_solution[0] < 1) return 1;
39433957
if (number_of_solutions == 2) {
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*******************************************************************************
2+
*
3+
* McStas, neutron ray-tracing package
4+
* Copyright(C) 2007 Risoe National Laboratory.
5+
*
6+
* %I
7+
* Written by: Mads Bertelsen
8+
* Date: 20.08.15
9+
* Version: $Revision: 0.1 $
10+
* Origin: University of Copenhagen
11+
*
12+
* A Mirror surface process
13+
*
14+
* %D
15+
*
16+
* This is a Union surface process that describes a supermirror or other surface
17+
* that only have specular reflection. The reflectivity can be given as a file
18+
* or using the standard reflectivity inputs. To use this in a simulation an
19+
* instance of this component should be defined in the instrument file, then
20+
* attatched to one or more geometries in their surface stacks pertaining to
21+
* each face of the geometry.
22+
*
23+
* Part of the Union components, a set of components that work together and thus
24+
* sperates geometry and physics within McStas.
25+
* The use of this component requires other components to be used.
26+
*
27+
* 1) One specifies a number of processes using process components like this one
28+
* 2) These are gathered into material definitions using Union_make_material
29+
* 3) Geometries are placed using Union_box / Union_cylinder, assigned a material
30+
* 4) A Union_master component placed after all of the above
31+
*
32+
* Only in step 4 will any simulation happen, and per default all geometries
33+
* defined before the master, but after the previous will be simulated here.
34+
*
35+
* There is a dedicated manual available for the Union_components
36+
*
37+
*
38+
* Algorithm:
39+
* Described elsewhere
40+
*
41+
* %P
42+
* INPUT PARAMETERS:
43+
* R0: [1] Low-angle reflectivity
44+
* Qc: [AA-1] Critical scattering vector
45+
* alpha: [AA] Slope of reflectivity
46+
* m: [1] m-value of material. Zero means completely absorbing.
47+
* W: [AA-1] Width of supermirror cut-off
48+
* reflect: [str] Name of reflectivity file. Format q(Angs-1) R(0-1)
49+
* init: [string] Name of Union_init component (typically "init", default)
50+
*
51+
* %L
52+
*
53+
* %E
54+
******************************************************************************/
55+
56+
DEFINE COMPONENT Mirror_surface // Remember to change the name of process here
57+
58+
SETTING PARAMETERS(string reflect=0, R0=0.99, Qc=0.0219, alpha=6.07, m=2, W=0.003, string init="init")
59+
60+
61+
SHARE
62+
%{
63+
#ifndef Union
64+
#error "The Union_init component must be included before this Mirror_surface component"
65+
#endif
66+
67+
68+
%include "read_table-lib"
69+
%include "ref-lib"
70+
71+
// Very important to add a pointer to this struct in the union-lib.c file
72+
struct Mirror_surface_storage_struct{
73+
// Variables that needs to be transfered between any of the following places:
74+
// The initialize in this component
75+
// The function for calculating my
76+
// The function for calculating scattering
77+
78+
// Avoid duplicates of setting parameters in naming
79+
double par[5];
80+
t_Table pTable;
81+
int table_present;
82+
};
83+
84+
// Function for handling surface physics
85+
// The input for this function and its order may not be changed, but the names may be updated.
86+
int Mirror_surface_function(union surface_data_transfer_union data_transfer, // data in struct defined above, can have data stored in initialize and other calls to this function
87+
double *weight, double *wavevector, int *continues, // given weight and wavevector, to be updated, and pointer to continues which should be provided by function
88+
double *normal_vector, enum in_or_out inward_or_outward, // normal_vector of surface and information on whether the neutron is going into or out of this surface
89+
_class_particle *_particle) {
90+
91+
// wavevector and normal_vector are a pointers to a simple array with 3 doubles, wavevector[0], wavevector[1], wavevector[2] which describes the vector
92+
93+
// Retrieve data storage struct
94+
struct Mirror_surface_storage_struct *storage;
95+
storage = data_transfer.pointer_to_a_Mirror_surface_storage_struct;
96+
97+
double k_n_dot = wavevector[0]*normal_vector[0] + wavevector[1]*normal_vector[1] + wavevector[2]*normal_vector[2];
98+
99+
// Calculate q normal
100+
double q_normal = 2.0*fabs(k_n_dot);
101+
102+
// Calculate or read reflectivity
103+
double reflectivity;
104+
if (storage->table_present == 1) {
105+
TableReflecFunc(q_normal, &storage->pTable, &reflectivity);
106+
} else {
107+
StdReflecFunc(q_normal, storage->par, &reflectivity);
108+
}
109+
110+
// Take monte carlo choice on whether to be reflected by the mirror or not
111+
if (rand01() > reflectivity) {
112+
*continues = 1; // Tells algorithm the ray goes through this surface
113+
} else {
114+
// mirror ray
115+
wavevector[0] = wavevector[0] - 2.0 * k_n_dot * normal_vector[0];
116+
wavevector[1] = wavevector[1] - 2.0 * k_n_dot * normal_vector[1];
117+
wavevector[2] = wavevector[2] - 2.0 * k_n_dot * normal_vector[2];
118+
119+
*continues = 0; // Tells algorithm the ray does not go through this surface
120+
}
121+
122+
return 1;
123+
124+
// There is access to the data_transfer from within this function:
125+
// int table_present = data_transfer.pointer_to_a_Mirror_physics_storage_struct->table_present;
126+
// Its even possible to write to this data structure and use results for a later ray if relevant
127+
};
128+
129+
// These lines help with future error correction, and tell other Union components
130+
// that at least one surface have been defined.
131+
#ifndef SURFACE_DETECTOR
132+
#define SURFACE_DETECTOR dummy
133+
#endif
134+
#ifndef SURFACE_PROCESS_MIRROR_DETECTOR
135+
#define SURFACE_PROCESS_MIRROR_DETECTOR dummy
136+
#endif
137+
%}
138+
139+
DECLARE
140+
%{
141+
// Declare for this component, to do calculations on the input / store in the transported data
142+
struct Mirror_surface_storage_struct Mirror_storage; // Replace Mirror with your own name here
143+
144+
// Needed for transport to the main component, will be the same for all surface processes
145+
struct global_surface_element_struct global_surface_element;
146+
struct surface_process_struct This_surface;
147+
%}
148+
149+
INITIALIZE
150+
%{
151+
// Initialize done in the component
152+
if (reflect && strlen(reflect) && strcmp(reflect,"NULL") && strcmp(reflect,"0")) {
153+
if (Table_Read(&Mirror_storage.pTable, reflect, 1) <= 0) /* read 1st block data from file into pTable */
154+
exit(fprintf(stderr,"Mirror_surface: %s: can not read file %s\n", NAME_CURRENT_COMP, reflect));
155+
Mirror_storage.table_present=1;
156+
} else {
157+
Mirror_storage.table_present=0;
158+
if (W < 0 || R0 < 0 || Qc < 0 || m < 0) {
159+
fprintf(stderr,"Mirror_surface: %s: W R0 Qc must be >0.\n", NAME_CURRENT_COMP);
160+
exit(-1);
161+
}
162+
}
163+
164+
// Insert input parameter to par array as required for the standard reflectivity function
165+
Mirror_storage.par[0] = R0;
166+
Mirror_storage.par[1] = Qc;
167+
Mirror_storage.par[2] = alpha;
168+
Mirror_storage.par[3] = m;
169+
Mirror_storage.par[4] = W;
170+
171+
// Will need to do similar system for surfaces
172+
// Need to specify if this process is isotropic
173+
//This_process.non_isotropic_rot_index = -1; // Yes (powder)
174+
//This_process.non_isotropic_rot_index = 1; // No (single crystal)
175+
//rot_copy(This_surface.rotation_matrix, ROT_A_CURRENT_COMP);
176+
177+
// The type of the process must be saved in the global enum process located in union-lib.c
178+
This_surface.eSurface = Mirror;
179+
180+
// Packing the data into a structure that is transported to the main component
181+
This_surface.data_transfer.pointer_to_a_Mirror_surface_storage_struct = &Mirror_storage;
182+
183+
// This will be the same for all process's, and can thus be moved to an include.
184+
sprintf(This_surface.name,"%s",NAME_CURRENT_COMP);
185+
sprintf(global_surface_element.name,"%s",NAME_CURRENT_COMP);
186+
global_surface_element.component_index = INDEX_CURRENT_COMP;
187+
global_surface_element.p_surface_process = &This_surface;
188+
189+
if (_getcomp_index(init) < 0) {
190+
fprintf(stderr,"Mirror_surface:%s: Error identifying Union_init component, %s is not a known component name.\n",
191+
NAME_CURRENT_COMP, init);
192+
exit(-1);
193+
}
194+
195+
struct pointer_to_global_surface_list *global_surface_list = COMP_GETPAR3(Union_init, init, global_surface_list);
196+
add_element_to_surface_list(global_surface_list, global_surface_element);
197+
%}
198+
199+
TRACE
200+
%{
201+
// Trace should be empty, the simulation is perfomed in Union_master
202+
%}
203+
204+
END
205+

0 commit comments

Comments
 (0)