| 150 | | /* determine intersection with inner and outer cylinders */ |
| 151 | | intersect=cylinder_intersect(&t0,&t3,x,y,z,vx,vy,vz,radius,yheight); |
| 152 | | if (!intersect) ABSORB; |
| 153 | | else if (t3 > t0) t0 = t3; |
| 154 | | |
| 155 | | intersect=cylinder_intersect(&t1,&t2,x,y,z,vx,vy,vz,radius+length,yheight); |
| 156 | | if (!intersect) ABSORB; |
| 157 | | else if (t2 > t1) t1 = t2; |
| 158 | | |
| 159 | | /* propagate/determine neutron position at inner cylinder */ |
| 160 | | if (t0 > 0 && t1 > t0) { |
| 161 | | double input_chan=0; |
| 162 | | double input_theta=0, output_theta=0; |
| 163 | | double roc_theta=0; |
| 164 | | double input_slit=0, output_slit=0; |
| 165 | | |
| 166 | | PROP_DT(t0); |
| 167 | | |
| 168 | | /* apply ROC oscillation with a linear random distribution */ |
| 169 | | if (roc) roc_theta = roc*randpm1()/2; else roc_theta=0; |
| 170 | | |
| 171 | | /* angle on inner cylinder */ |
| 172 | | input_theta = atan2(x, z) + roc_theta; |
| 173 | | |
| 174 | | /* check if we are within min/max collimator input bounds */ |
| 175 | | if (input_theta >= theta_min && input_theta <= theta_max) { |
| 176 | | SCATTER; |
| 177 | | /* input Soller channel index */ |
| 178 | | if (width_of_Soller) { |
| 179 | | input_chan = radius*(input_theta-theta_min)/width_of_Soller; |
| 180 | | input_chan = input_chan-floor(input_chan); /* position within Soller [0:1] */ |
| | 150 | |
| | 151 | if (width_of_slit && nslit) { |
| | 152 | /* determine intersection with inner and outer cylinders */ |
| | 153 | intersect=cylinder_intersect(&t0,&t3,x,y,z,vx,vy,vz,radius,yheight); |
| | 154 | if (!intersect) ABSORB; |
| | 155 | else if (t3 > t0) t0 = t3; |
| | 156 | |
| | 157 | intersect=cylinder_intersect(&t1,&t2,x,y,z,vx,vy,vz,radius+length,yheight); |
| | 158 | if (!intersect) ABSORB; |
| | 159 | else if (t2 > t1) t1 = t2; |
| | 160 | |
| | 161 | /* propagate/determine neutron position at inner cylinder */ |
| | 162 | if (t0 > 0 && t1 > t0) { |
| | 163 | double input_chan=0; |
| | 164 | double input_theta=0, output_theta=0; |
| | 165 | double roc_theta=0; |
| | 166 | double input_slit=0, output_slit=0; |
| | 167 | |
| | 168 | PROP_DT(t0); |
| | 169 | |
| | 170 | /* apply ROC oscillation with a linear random distribution */ |
| | 171 | if (roc) roc_theta = roc*randpm1()/2; else roc_theta=0; |
| | 172 | |
| | 173 | /* angle on inner cylinder */ |
| | 174 | input_theta = atan2(x, z) + roc_theta; |
| | 175 | |
| | 176 | /* check if we are within min/max collimator input bounds */ |
| | 177 | if (input_theta >= theta_min && input_theta <= theta_max) { |
| | 178 | SCATTER; |
| | 179 | /* input Soller channel index */ |
| | 180 | if (width_of_Soller) { |
| | 181 | input_chan = radius*(input_theta-theta_min)/width_of_Soller; |
| | 182 | input_chan = input_chan-floor(input_chan); /* position within Soller [0:1] */ |
| | 183 | |
| | 184 | /* check if we hit an absorbing housing (between Sollers): ABSORB |
| | 185 | * total Soller aperture is width_of_Soller, |
| | 186 | * containg a slit pack of aperture xwidth |
| | 187 | */ |
| | 188 | if (input_chan < (1-xwidth/width_of_Soller)/2 |
| | 189 | || input_chan > (1+xwidth/width_of_Soller)/2) ABSORB; |
| | 190 | } |
| | 191 | |
| | 192 | /* determine input slit index */ |
| | 193 | input_slit = floor(input_theta*radius/width_of_slit); |
| 182 | | /* check if we hit an absorbing housing (between Sollers): ABSORB |
| 183 | | * total Soller aperture is width_of_Soller, |
| 184 | | * containg a slit pack of aperture xwidth |
| 185 | | */ |
| 186 | | if (input_chan < (1-xwidth/width_of_Soller)/2 |
| 187 | | || input_chan > (1+xwidth/width_of_Soller)/2) ABSORB; |
| 188 | | } |
| 189 | | |
| 190 | | /* determine input slit index */ |
| 191 | | input_slit = floor(input_theta*radius/width_of_slit); |
| 192 | | |
| 193 | | } else /* neutron missed collimator input range */ |
| 194 | | input_theta=4*PI; |
| 195 | | |
| 196 | | /* propagate to outer cylinder */ |
| 197 | | PROP_DT(t1-t0); |
| 198 | | |
| 199 | | /* angle on outer cylinder */ |
| 200 | | output_theta = atan2(x, z) + roc_theta; |
| 201 | | |
| 202 | | /* check if we are within min/max collimator output bounds */ |
| 203 | | if (output_theta >= theta_min && output_theta <= theta_max) { |
| 204 | | /* check if we come from sides: ABSORB */ |
| 205 | | if (input_theta > 2*PI) ABSORB; /* input_theta=4*PI when missed input */ |
| 206 | | |
| 207 | | if (approx) { |
| 208 | | double phi=atan2(x, z)-atan2(vx, vz); /* difference between positional slit angle and velocity */ |
| 209 | | if (fabs(phi) > divergence) |
| 210 | | ABSORB; /* get outside transmission */ |
| 211 | | else |
| 212 | | p *= (1.0 - phi/divergence); |
| 213 | | } else { |
| 214 | | /* check if we have changed slit: ABSORB */ |
| 215 | | /* slits are considered radial so that their output size is: |
| 216 | | width_of_slit*(radius+length)/radius and it turns out this the same exp as for input |
| 217 | | */ |
| 218 | | output_slit = floor(output_theta*radius/width_of_slit); |
| 219 | | if (input_slit != output_slit) ABSORB; |
| 220 | | } |
| 221 | | SCATTER; |
| 222 | | p *= transmission; |
| 223 | | |
| 224 | | } /* else neutron missed collimator output range */ |
| 225 | | |
| 226 | | } /* else did not encounter collimator cylinders */ |
| | 195 | } else /* neutron missed collimator input range */ |
| | 196 | input_theta=4*PI; |
| | 197 | |
| | 198 | /* propagate to outer cylinder */ |
| | 199 | PROP_DT(t1-t0); |
| | 200 | |
| | 201 | /* angle on outer cylinder */ |
| | 202 | output_theta = atan2(x, z) + roc_theta; |
| | 203 | |
| | 204 | /* check if we are within min/max collimator output bounds */ |
| | 205 | if (output_theta >= theta_min && output_theta <= theta_max) { |
| | 206 | /* check if we come from sides: ABSORB */ |
| | 207 | if (input_theta > 2*PI) ABSORB; /* input_theta=4*PI when missed input */ |
| | 208 | |
| | 209 | if (approx) { |
| | 210 | double phi=atan2(x, z)-atan2(vx, vz); /* difference between positional slit angle and velocity */ |
| | 211 | if (fabs(phi) > divergence) |
| | 212 | ABSORB; /* get outside transmission */ |
| | 213 | else |
| | 214 | p *= (1.0 - phi/divergence); |
| | 215 | } else { |
| | 216 | /* check if we have changed slit: ABSORB */ |
| | 217 | /* slits are considered radial so that their output size is: |
| | 218 | width_of_slit*(radius+length)/radius and it turns out this the same exp as for input |
| | 219 | */ |
| | 220 | output_slit = floor(output_theta*radius/width_of_slit); |
| | 221 | if (input_slit != output_slit) ABSORB; |
| | 222 | } |
| | 223 | SCATTER; |
| | 224 | p *= transmission; |
| | 225 | |
| | 226 | } /* else neutron missed collimator output range */ |
| | 227 | |
| | 228 | } /* else did not encounter collimator cylinders */ |
| | 229 | } /* if nslit */ |