Skip to content

Commit 7a9f487

Browse files
Fixed bugs in union-lib.c relating to calculation of normal vectors for box and cylinder.
Added possibility to specify scattering length density directly in Union_make_material, and simplified memory structure to primarily store SLD instead of more variables used to calculate it. Improved debug prints in Union_master and adopted use of SLD.
1 parent 43db2aa commit 7a9f487

File tree

4 files changed

+125
-105
lines changed

4 files changed

+125
-105
lines changed

mcstas-comps/share/union-lib.c

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,7 @@ struct scattering_process_struct *p_scattering_array;
471471

472472
// refraction related
473473
int has_refraction_info;
474-
double refraction_rho;
475-
double refraction_bc;
474+
double refraction_scattering_length_density; // [AA^-2]
476475
double refraction_Qc;
477476
};
478477

@@ -2646,11 +2645,7 @@ int sample_box_intersect_advanced(double *t, double *nx, double *ny, double *nz,
26462645
Coords normal_vector_rotated;
26472646
Coords normal_vector;
26482647

2649-
2650-
// Rotate back to master coordinate system
2651-
normal_vector_rotated = coords_set(nx[0], nx[1], nx[2]);
2652-
normal_vector = rot_apply(geometry->rotation_matrix, normal_vector_rotated);
2653-
2648+
// Sort solution according to intersection time and rotate normal vectors to master coordinate system
26542649
switch(*num_solutions) {
26552650
case 2:
26562651
if (t[0] > t[1]) {
@@ -2668,7 +2663,7 @@ int sample_box_intersect_advanced(double *t, double *nx, double *ny, double *nz,
26682663
ny[0] = temp;
26692664

26702665
temp = nz[1];
2671-
nz[1] = nx[0];
2666+
nz[1] = nz[0];
26722667
nz[0] = temp;
26732668

26742669
// Switch surface_index
@@ -4127,7 +4122,7 @@ int sample_cylinder_intersect(double *t, double *nx, double *ny, double *nz, int
41274122
double radius = geometry->geometry_parameters.p_cylinder_storage->cyl_radius;
41284123
double height = geometry->geometry_parameters.p_cylinder_storage->height;
41294124

4130-
// Declare variables for the function
4125+
// Declare position variables for the local coordinate system
41314126
double x_new,y_new,z_new;
41324127

41334128
// Coordinate transformation
@@ -4137,69 +4132,77 @@ int sample_cylinder_intersect(double *t, double *nx, double *ny, double *nz, int
41374132

41384133
Coords coordinates = coords_set(x_new,y_new,z_new);
41394134
Coords rotated_coordinates;
4140-
// printf("Cords coordinates = (%f,%f,%f)\n",coordinates.x,coordinates.y,coordinates.z);
4141-
4142-
// debug
4143-
// Rotation rotation_matrix_debug[3][3];
4144-
// rot_set_rotation(rotation_matrix_debug,-1.0*geometry->rotation.x,-1.0*geometry->rotation.y,-1.0*geometry->rotation.z);
4145-
// rot_transpose(geometry->rotation_matrix,rotation_matrix_debug);
41464135

41474136
// Rotate the position of the neutron around the center of the cylinder
41484137
rotated_coordinates = rot_apply(geometry->transpose_rotation_matrix,coordinates);
4149-
// rotated_coordinates = rot_apply(rotation_matrix_debug,coordinates);
4150-
// printf("Cords rotated_coordinates = (%f,%f,%f)\n",rotated_coordinates.x,rotated_coordinates.y,rotated_coordinates.z);
41514138

41524139
Coords velocity = coords_set(v[0],v[1],v[2]);
41534140
Coords rotated_velocity;
4154-
// printf("Cords velocity = (%f,%f,%f)\n",velocity.x,velocity.y,velocity.z);
41554141

41564142
// Rotate the position of the neutron around the center of the cylinder
41574143
rotated_velocity = rot_apply(geometry->transpose_rotation_matrix,velocity);
4158-
// rotated_velocity = rot_apply(rotation_matrix_debug,velocity);
4159-
// printf("Cords rotated_velocity = (%f,%f,%f)\n",rotated_velocity.x,rotated_velocity.y,rotated_velocity.z);
4160-
4161-
4162-
4163-
// Cases where the velocity is parallel with the cylinder axis have given problems, and is checked for explicitly
4164-
if (sqrt(rotated_velocity.x*rotated_velocity.x+rotated_velocity.z*rotated_velocity.z)/fabs(rotated_velocity.y) < 0.00001) {
4165-
// The velocity is parallel with the cylinder axis. Either there is two solutions
4166-
if (sqrt(rotated_coordinates.x*rotated_coordinates.x+rotated_coordinates.z*rotated_coordinates.z) > radius) {
4167-
*num_solutions = 0;
4168-
return 0;
4169-
} else {
4170-
*num_solutions = 2;
4171-
t[0] = (0.5*height - rotated_coordinates.y)/rotated_velocity.y;
4172-
t[1] = (-0.5*height - rotated_coordinates.y)/rotated_velocity.y;
4173-
return 1;
4174-
}
4175-
}
41764144

4177-
int output;
4178-
// Run McStas built in sphere intersect funtion (sphere centered around origin)
4179-
if ((output = cylinder_intersect(&t[0],&t[1],
4180-
rotated_coordinates.x,rotated_coordinates.y,rotated_coordinates.z,
4181-
rotated_velocity.x,rotated_velocity.y,rotated_velocity.z,radius,height)) == 0) {
4182-
*num_solutions = 0;t[0]=-1;t[1]=-1;
4183-
}
4184-
else if (t[1] != 0) *num_solutions = 2;
4185-
else {*num_solutions = 1; t[1]=-1;}
4145+
int output;
4146+
// Cases where the velocity is parallel with the cylinder axis have given problems, and is checked for explicitly
4147+
if (sqrt(rotated_velocity.x*rotated_velocity.x+rotated_velocity.z*rotated_velocity.z)/fabs(rotated_velocity.y) < 0.00001) {
4148+
// The velocity is parallel with the cylinder axis. Either there are no solutions or two solutions
4149+
if (sqrt(rotated_coordinates.x*rotated_coordinates.x+rotated_coordinates.z*rotated_coordinates.z) > radius) {
4150+
*num_solutions = 0;
4151+
return 0;
4152+
} else {
4153+
*num_solutions = 2;
4154+
t[0] = (0.5*height - rotated_coordinates.y)/rotated_velocity.y;
4155+
surface_index[0] = 1; // index indicating top
4156+
4157+
t[1] = (-0.5*height - rotated_coordinates.y)/rotated_velocity.y;
4158+
surface_index[1] = 2; // index indicating bottom
4159+
4160+
// sort solutions
4161+
if (t[0] > t[1]) {
4162+
double d_temp;
4163+
4164+
d_temp = t[0];
4165+
t[0] = t[1];
4166+
t[1] = d_temp;
4167+
4168+
int i_temp;
4169+
4170+
i_temp = surface_index[0];
4171+
surface_index[0] = surface_index[1];
4172+
surface_index[1] = i_temp;
4173+
}
4174+
}
4175+
} else {
4176+
// velocity not parallel to cylinder axis, call standard mcstas cylinder intersect
4177+
4178+
// Run McStas built in sphere intersect funtion (sphere centered around origin)
4179+
if ((output = cylinder_intersect(&t[0],&t[1],
4180+
rotated_coordinates.x,rotated_coordinates.y,rotated_coordinates.z,
4181+
rotated_velocity.x,rotated_velocity.y,rotated_velocity.z,radius,height)) == 0) {
4182+
*num_solutions = 0;t[0]=-1;t[1]=-1;
4183+
}
4184+
else if (t[1] != 0) *num_solutions = 2;
4185+
else {*num_solutions = 1; t[1]=-1;}
41864186

4187-
// decode output value
4188-
// Check the bitmask for entry and exit
4189-
if (*num_solutions > 0) {
4190-
int entry_index = 0;
4191-
if (output & 2) entry_index = 1; // Entry intersects top cap
4192-
if (output & 4) entry_index = 2; // Entry intersects bottom cap
4193-
surface_index[0] = entry_index;
4194-
}
4187+
// decode output value
4188+
// Check the bitmask for entry and exit
4189+
if (*num_solutions > 0) {
4190+
int entry_index = 0;
4191+
if (output & 2) entry_index = 1; // Entry intersects top cap
4192+
if (output & 4) entry_index = 2; // Entry intersects bottom cap
4193+
surface_index[0] = entry_index;
4194+
}
41954195

4196-
if (*num_solutions > 1) {
4197-
int exit_index = 0;
4198-
if (output & 8) exit_index = 1; // Exit intersects top cap
4199-
if (output & 16) exit_index = 2; // Exit intersects bottom cap
4200-
surface_index[1] = exit_index;
4196+
if (*num_solutions > 1) {
4197+
int exit_index = 0;
4198+
if (output & 8) exit_index = 1; // Exit intersects top cap
4199+
if (output & 16) exit_index = 2; // Exit intersects bottom cap
4200+
surface_index[1] = exit_index;
4201+
}
42014202
}
4203+
42024204

4205+
// Calculate normal vectors from surface index and cylinder geometry
42034206
int index;
42044207
double x, y, z, dt;
42054208
Coords normal_vector_rotated;
@@ -4238,7 +4241,7 @@ int sample_cylinder_intersect(double *t, double *nx, double *ny, double *nz, int
42384241
};
42394242

42404243
int r_within_cylinder(Coords pos,struct geometry_struct *geometry) {
4241-
// Unpack parameters
4244+
// Unpack parameters
42424245
double radius = geometry->geometry_parameters.p_cylinder_storage->cyl_radius;
42434246
double height = geometry->geometry_parameters.p_cylinder_storage->height;
42444247

mcstas-comps/union/Single_crystal_process.comp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,8 @@
5454
* cy: [AA or AA^-1] c on y axis
5555
* cz: [AA or AA^-1] c on z axis
5656
* reflections: [string] File name containing structure factors of reflections. Use empty ("") or NULL for incoherent scattering only
57-
* order: [1] Limit multiple scattering up to given order (0: all, 1: first, 2: second, ...)
57+
* order: [1] Limit multiple scattering up to given order (0: all, 1: first, 2: second, ...) (Not supported in Union)
5858
* p_transmit: [1] Monte Carlo probability for neutrons to be transmitted without any scattering. Used to improve statistics from weak reflections
59-
* sigma_abs: [barns] Absorption cross-section per unit cell at 2200 m/s
60-
* sigma_inc: [barns] Incoherent scattering cross-section per unit cell Use -1 to inactivate
6159
* aa: [deg] Unit cell angles alpha, beta and gamma. Then uses norms of vectors a,b and c as lattice parameters
6260
* bb: [deg] Beta angle
6361
* cc: [deg] Gamma angle

mcstas-comps/union/Union_make_material.comp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* refraction_sigma_coh: [barn] coherent cross section of refracting material. Use negative value to indicate a negative coherent scattering length
3838
* refraction_density: [g/cm3] density of the refracting material. density < 0 means the material is outside/before the shape.
3939
* refraction_weight: [g/mol] molar mass of the refracting material
40+
* refraction_SLD: [AA^-2] scattering length density of material (overwrites sigma_coh, density and weight)
4041
* init: [string] Name of Union_init component (typically "init", default)
4142
*
4243
* CALCULATED PARAMETERS:
@@ -53,7 +54,10 @@
5354

5455
DEFINE COMPONENT Union_make_material
5556

56-
SETTING PARAMETERS(string process_string="NULL", my_absorption,absorber=0, refraction_density=0, refraction_sigma_coh=0, refraction_weight=0, string init="init")
57+
SETTING PARAMETERS(string process_string="NULL", my_absorption,absorber=0,
58+
refraction_density=0, refraction_sigma_coh=0, refraction_weight=0,
59+
refraction_SLD=-1500,
60+
string init="init")
5761

5862

5963
/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */
@@ -237,22 +241,32 @@ struct pointer_to_global_process_list *global_process_list = COMP_GETPAR3(Union_
237241

238242
this_material.has_refraction_info = 0;
239243
if (refraction_density != 0 || refraction_weight != 0 || refraction_sigma_coh != 0) {
244+
245+
double refraction_rho, refraction_bc;
240246
if (refraction_density==0 || refraction_weight<=0)
241247
exit(printf("Union_make_material: %s: FATAL: invalid material density or molar weight: density=%g weight=%g\n",
242248
NAME_CURRENT_COMP, refraction_density, refraction_weight));
243-
this_material.refraction_rho = fabs(refraction_density)*6.02214179*1e23*1e-24/refraction_weight; // per at/Angs^3
249+
250+
refraction_rho = fabs(refraction_density)*6.02214179*1e23*1e-24/refraction_weight; // per at/Angs^3
244251

245252
if (refraction_sigma_coh==0)
246253
exit(printf("Refractor: %s: FATAL: invalid material coherent cross section: sigma_coh=%g\n",
247254
NAME_CURRENT_COMP, refraction_sigma_coh));
248-
this_material.refraction_bc = sqrt(fabs(refraction_sigma_coh)*100/4/PI)*1e-5; // bound coherent scattering length
249-
if (refraction_sigma_coh<0) this_material.refraction_bc *= -1;
250-
251-
this_material.refraction_Qc = 4*sqrt(PI*this_material.refraction_rho*fabs(this_material.refraction_bc));
252-
255+
256+
refraction_bc = sqrt(fabs(refraction_sigma_coh)*100/4/PI)*1e-5; // bound coherent scattering length
257+
if (refraction_sigma_coh<0) refraction_bc *= -1.0;
258+
259+
this_material.refraction_scattering_length_density = refraction_rho*refraction_bc;
260+
this_material.refraction_Qc = 4*sqrt(PI*refraction_rho*fabs(refraction_bc));
253261
this_material.has_refraction_info = 1;
254262
}
255263

264+
if (refraction_SLD > -1499.0) { // refraction_SLD can be negative, zero or positive, it can however not be this negative, so this is used as input check
265+
this_material.refraction_scattering_length_density = refraction_SLD;
266+
this_material.refraction_Qc = 4.0*sqrt(PI*fabs(refraction_SLD));
267+
this_material.has_refraction_info = 1;
268+
}
269+
256270
// packing the information into the global_material_element, which is then included in the global_material_list.
257271
sprintf(global_material_element.name,"%s",NAME_CURRENT_COMP);
258272
global_material_element.component_index = INDEX_CURRENT_COMP;

0 commit comments

Comments
 (0)