1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
/*******************************************************************************
*
* McStas, neutron ray-tracing package
* Copyright 1997-2002, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Component: my_component
*
* %IDENTIFICATION
* Written by: Erik B Knudsen
* Date: Sep. 2015
* Origin: DTU Physics
* Modified by:
*
* %DESCRIPTION
* A magnet with a spin-flip foil inside
*
* This component models a magnet with a constant magnetic field and a slanted
* magnetized foil inside acting as a spin-flipper. This arrangement may be used to
* target the geometry of a Spin-Echo SANS instrument (Rekveldt, NIMB, 1997 || Rekveldt, Rev Sci Instr. 2005).
* In its most basic form a SE-SANS instrument nrelies on inclined field regions of
* constant magnetic field, which can be difficult to realize. Instead it is possible to emulate
* such regions using a magnetized foil.
*
* In this component th emagntzied foil is modelled as a canted (by the angle phi) mathematical plane inside a region
* of constant magnetic field of dimensions (xwidth,yheight,zdepth). Furthermore, exponetially decaying stray fields from
* the constant field region may be specified by giving parameters (Bxwidth,Byheight,Bzdepth) > (xwidth,yheight,zdepth).
*
*
* %PARAMETERS
* xwidth: [m] width of the magnet
* yheight: [m] height of the magnet
* zdepth: [m] thickness of the magnet
* Bxwidth: [m] width of the B-field of thev component
* Byheight: [m] height of the B-field of the component
* Bzdepth: [m] thickness of the B-field of the component
* phi: [rd] angle (from the xz-plane) of the foil-spinflipper inside the magnet
* foilthick: [um] Thickness of the magnetized foil
* Bx: [T] Parameter used for x composant of field.
* By: [T] Parameter used for y composant of field.
* Bz: [T] Parameter used for z composant of field.
* stray_field: [ ] Toggle for modelling of stray fields.
* verbose: [ ] Toggle verbose mode
* foil_in: [ ] Toggle for optional foil in the flipper.
*
* %LINKS
*
* %END
****************************************************************************/
/*
This comment will not be exported to mcdoc
*/
DEFINE COMPONENT Foil_flipper_magnet
SETTING PARAMETERS(stray_field=1,xwidth, yheight, zdepth, Bxwidth=-1, Byheight=-1, Bzdepth=-1, phi=0.0, foilthick=0.0, Bx,By,Bz,foil_in=1, verbose=0)
SHARE
%{
/* Declare structures and functions only once in each instrument. */
#ifndef POL_LIB_H
%include "pol-lib"
#endif
#pragma acc routine
void foil_spin_rot(double *sx, double *sy, double *sz, double *vx, double *vy, double *vz, double phi, double th, double b){
/*the spin flip is actually a precession around the field vector - in this case this vector is
* in the foil plane, perp. to X, i.e. Z rotated by phi.*/
double ux,uy,uz,s,cx,cy,cz;
double theta,v,lamb,teff;
/*now use (0,0,1) as a vector to rotate (flip) around to mimic the use of correction coils.*/
ux=uy=0;uz=1;
//ux=0;uy=sin(phi);uz=cos(phi);
if (b < 0) {
uy = -uy;
uz = -uz;
}
v=sqrt(*vx * *vx + *vy * *vy + *vz * *vz);
lamb = 2*PI*K2V/v;
teff = th/sin(phi);
/* Calculate the flipping angle theta by c*t*Bs*lambda
* where c is the neutron precession constant [T^-1*m^-2], t is the
* foil thickness [um], Bs is the induced magnetic field strength
* in the foil [T] and lambda is the neutron wavelength [m] */
theta = 4.6368*1e14*teff*1e-6*1*lamb*1e-10;
/*Rodigues formula for roatating a vector around a unit vector.
* v_rot=v*cos(theta) + uxv * sin(theta) + (u dot v)u(1-cos(theta)*/
cx=*sz*uy-*sy*uz;
cy=*sx*uz-*sz*ux;
cz=*sy*ux-*sx*uy;
s=scalar_prod(ux,uy,uz,*sx,*sy,*sz);
*sx=*sx*cos(theta) + cx*sin(theta) + s*ux*(1-cos(theta));
*sy=*sy*cos(theta) + cy*sin(theta) + s*uy*(1-cos(theta));
*sz=*sz*cos(theta) + cz*sin(theta) + s*uz*(1-cos(theta));
}
#pragma acc routine
void foil_spin_flip(double *sx, double *sy, double *sz, double lamb, double phi){
/*the spin flip is actually a precession around the field vector - in this case this vector is
* in the foil plane, perp. to X, i.e. Z rotated by phi.*/
double ux,uy,uz,s;
ux=0;uy=sin(phi);uz=cos(phi);
/*Rodigues formula for roatating a vector around a unit vector.
* v_rot=v*cos(theta) + uxv * sin(theta) + (u dot v)u(1-cos(theta)
* theta=180 deg. => v_rot =-v + 2*(u dot v)u*/
s=scalar_prod(ux,uy,uz,*sx,*sy,*sz);
*sx=-*sx+2*s*ux;
*sy=-*sy+2*s*uy;
*sz=-*sz+2*s*uz;
}
int exp_dec_magnetic_field (double x, double y, double z, double t, double *Bx, double *By, double *Bz, void *data){
double *prms = (double *)data;
double b;
/*parameters are in the order, Bx0,By0,Bz0,z0, where z0 is the point from which B is decaying*/
if(z<prms[3]){
b=1;
}else{
b=exp(- fabs(z-prms[3]));
}
*Bx=prms[0]*b;
*By=prms[1]*b;
*Bz=prms[2]*b;
}
%}
DECLARE
%{
/*Declarations of variables used in the whole of the component*/
void *magnet_prms;
double foil_n[3];
Rotation spin_flip;
double inside_magnet[3];
double instray_magnet[4];
double outstray_magnet[4];
int hit_foil;
%}
INITIALIZE
%{
/*default is to have the foil horizontal*/
Rotation foil_rot;
Coords n,tmp;
n.x=0;n.y=1;n.z=0;
rot_set_rotation(foil_rot,phi,0,0);
tmp=rot_apply(foil_rot,n);
foil_n[0]=tmp.x;foil_n[1]=tmp.y; foil_n[2]=tmp.z;
/*setup spin-flip rotation. This is equivalent to mirroring in the foil plane.*/
if(verbose){
printf("INFO: (%s) Foil normal: (%g %g %g)\n",NAME_CURRENT_COMP, foil_n[0],foil_n[1],foil_n[2]);
}
/*copy-paste from simpleBfield.comp*/
/*this should be a store_magnet type function in pol-lib i think*/
Coords localG = rot_apply(ROT_A_CURRENT_COMP, coords_set(0,-GRAVITY,0));
/*initialize magnet parameters*/
instray_magnet[1]=By;
instray_magnet[2]=Bz;
instray_magnet[3]=-zdepth/2.0;
outstray_magnet[0]=Bx;
outstray_magnet[1]=By;
outstray_magnet[2]=Bz;
outstray_magnet[3]=zdepth/2.0;
inside_magnet[0]=Bx;
inside_magnet[1]=By;
inside_magnet[2]=Bz;
/*if the magnetic field dimensions are not given, we assume there are no stray fields.
I.e. the magnetic field does not extend beyond the magnet gap*/
/* if (Bxwidth!=-1 && Byheight!=-1 && Bzdepth!=-1){*/
/* stray_field=1;*/
/* }*/
if (Bxwidth==-1) Bxwidth=xwidth;
if (Byheight==-1) Byheight=yheight;
if (Bzdepth==-1) Bzdepth=zdepth;
if (verbose){
printf("INFO (%s): xw,yh,zd=(%g %g %g), (Bxw,Byh,Bzd)=(%g %g %g)\n",NAME_CURRENT_COMP,xwidth,yheight,zdepth,Bxwidth,Byheight,Bzdepth);
if (foil_in) printf("INFO (%s): Foil is IN\n",NAME_CURRENT_COMP);
else printf("INFO (%s): Foil is OUT\n", NAME_CURRENT_COMP);
}
%}
TRACE
%{
double t1,t2,t3,t4,dt;
double sp,v;
mcmagnet_field_info *old_magnet,*outer_magnet;
double *dd;
v=sqrt(vx*vx + vy*vy + vz*vz);
/*check if we hit component at all*/
if (plane_intersect(&t1,x,y,z,vx,vy,vz,0,0,1,0,0,-Bzdepth/2.0)==0){
if(verbose) fprintf(stderr,"INFO: (%s) Missed the magnetic field plane.\n",NAME_CURRENT_COMP);
ABSORB;
}
if ( (box_intersect(&t1, &t2, x, y, z, vx, vy, vz, Bxwidth, Byheight, Bzdepth))==0){
/*propagate to the start of the component (which is -Bzdepth/2)*/
if(verbose) fprintf(stderr,"INFO: (%s) Missed the magnetic field.\n",NAME_CURRENT_COMP);
ABSORB;
}
if (t1<0){
if(verbose) fprintf(stderr,"WARNING (%s): Neutron is already inside component on entry.\n",NAME_CURRENT_COMP);
}else{
PROP_DT(t1);
t2=t2-t1;
}
/*There is an implicit assumption here that the neutron has entered at z<zd/2. This might not be true.*/
if (stray_field){
/*neutron is now at the start of our b-field description*/
/*this would be the place to push the magnetic field description from the magnet stack*/
/*inject our magnet description into the propagation and remember the old one*/
mcmagnet_push(_particle,0,&(ROT_A_CURRENT_COMP),&(POS_A_CURRENT_COMP),0,instray_magnet);
}
/*do we hit the magnet opening assuming the magnet gap "tunnel" is rectangular*/
if ( (box_intersect(&t3, &t4, x, y, z, vx, vy, vz,xwidth, yheight, zdepth))==0){
if(verbose) fprintf(stdout,"INFO: (%s) Missed the magnet gap\n",NAME_CURRENT_COMP);
ABSORB;
}
/* t3 is the time for intersecting the first part of the area under the magnet - propagate to that*/
if (t3>1e-9){
PROP_DT(t3);
t4=t4-t3;
t2=t2-t3;
}
/*pop out the stray field description if necessary*/
if(stray_field) mcmagnet_pop(_particle);//this could be done with a stop bit in the magnet parameters
/*inject another field description for the magnetic field betweeen pole shoes.*/
mcmagnet_push(_particle,constant,&(ROT_A_CURRENT_COMP),&(POS_A_CURRENT_COMP),1,inside_magnet);
/*see if we hit the magnet walls before we exit*/
if (plane_intersect(&dt,x,y,z,vx,vy,vz,0,0,1,0,0,zdepth/2.0)==0){
fprintf(stdout,"INFO: (%s) Missed the end plane of the magnet - this should not be\n",NAME_CURRENT_COMP);
ABSORB;
}
if (fabs(dt-t4)>FLT_EPSILON) {
if(verbose) fprintf(stdout,"INFO: (%s) hit magnet from inside gap.\n",NAME_CURRENT_COMP);
mcmagnet_pop(_particle);
ABSORB;
}
/*neutron is inside magnet gap - propagate to the foil plane or leave the neutron if it does not hit the plane
while inside the gap*/
if (foil_in){
if (plane_intersect(&dt,x,y,z,vx,vy,vz,foil_n[0],foil_n[1],foil_n[2],0,0,0)==0 || dt<0 || dt>t4 ){
if(verbose) fprintf(stderr,"INFO: (%s) Missed the foil flipper plane, (dt=%g).\n",NAME_CURRENT_COMP,dt);
dt=dt;
hit_foil=0;
}
else{
PROP_DT(dt);
t4=t4-dt;
t2=t2-dt;
/* at the foil - so flip spin/polarization*/
if (foilthick == 0.0){
foil_spin_flip(&sx,&sy,&sz,0.0,phi);
}else{
foil_spin_rot(&sx , &sy , &sz , &vx , &vy , &vz , phi , foilthick, By);
}
hit_foil=1;
}
}
/*propagate to the other end of the magnet gap*/
PROP_DT(t4);
t2=t2-t4;
/*pop the "inner" magnetic field*/
mcmagnet_pop(_particle);
if(stray_field)
mcmagnet_push(_particle,0,&(ROT_A_CURRENT_COMP),&(POS_A_CURRENT_COMP),0,outstray_magnet);
if (t2>1e-9){
/*propagate to the end of the component*/
PROP_DT(t2);
}
/*pop the 2nd stray field*/
if(stray_field){
mcmagnet_pop(_particle);
}
%}
MCDISPLAY
%{
double y=atan(phi)*zdepth/2.0;
box(0.0,0.0,0.0,Bxwidth,Byheight,Bzdepth,0, 0, 1, 0);
if (Bxwidth!=xwidth || Byheight!=yheight || Bzdepth!=zdepth){
box(0,0,0,xwidth,yheight,zdepth,0, 0, 1, 0);
}
/*draw the foil plane*/
multiline(5,-xwidth/2.0,-y,-zdepth/2.0, xwidth/2.0,-y,-zdepth/2.0, xwidth/2.0,y,zdepth/2.0, -xwidth/2.0,y,zdepth/2.0, -xwidth/2.0,-y,-zdepth/2.0);
%}
END
|