File: Foil_flipper_magnet.comp

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,113,256 kB
  • sloc: ansic: 40,697; python: 25,137; yacc: 8,438; sh: 5,405; javascript: 4,596; lex: 1,632; cpp: 742; perl: 296; lisp: 273; makefile: 226; fortran: 132
file content (300 lines) | stat: -rw-r--r-- 10,776 bytes parent folder | download
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