/****************************************************************************** * elliosoid_intersect: Calculate intersection between a line and an ellipsoid. * They ellisoid is fixed by a set of half-axis (a,b,c) and a matrix Q, with the * columns of Q being the (orthogonal) vectors along which the half-axis lie. * This allows for complete freedom in orienting th eellipsoid. * returns 0 when no intersection is found * or 1 when they are found with resulting lemngths l0 and l1. *****************************************************************************/ int ellipsoid_intersect(double *l0, double *l1, double x, double y, double z, double kx, double ky, double kz, double a, double b, double c, Rotation Q) { Rotation A,Gamma,Q_t,Tmp; double u,v,w; Gamma[0][0]=Gamma[0][1]=Gamma[0][2]=0; Gamma[1][1]=Gamma[1][0]=Gamma[1][2]=0; Gamma[2][2]=Gamma[2][0]=Gamma[2][1]=0; /*now set diagonal to ellipsoid half axis if non-zero. * This way a zero value mean the sllipsoid extends infinitely along that axis, * which is useful for objects only curved in one direction*/ if (a!=0){ Gamma[0][0]=1/(a*a); } if (b!=0){ Gamma[1][1]=1/(b*b); } if (c!=0){ Gamma[2][2]=1/(c*c); } if (Q!=NULL){ rot_transpose(Q,Q_t); rot_mul(Gamma,Q_t,Tmp); rot_mul(Q,Tmp,A); }else{ rot_copy(A,Gamma); } /*to get the solutions as lengths in m use unit vector along k*/ double ex,ey,ez,k; k=sqrt(kx*kx+ky*ky+kz*kz); ex=kx/k; ey=ky/k; ez=kz/k; u=ex*(A[0][0]*ex + A[1][0]*ey + A[2][0]*ez) + ey*( A[0][1]*ex + A[1][1]*ey + A[2][1]*ez) + ez*(A[0][2]*ex + A[1][2]*ey + A[2][2]*ez); v=x *(A[0][0]*ex + A[1][0]*ey + A[2][0]*ez) + ex*(A[0][0]*x + A[1][0]*y + A[2][0]*z) + y *(A[0][1]*ex + A[1][1]*ey + A[2][1]*ez) + ey*(A[0][1]*x + A[1][1]*y + A[2][1]*z) + z *(A[0][2]*ex + A[1][2]*ey + A[2][2]*ez) + ez*(A[0][2]*x + A[1][2]*y + A[2][2]*z); w=x*(A[0][0]*x + A[1][0]*y + A[2][0]*z) + y*(A[0][1]*x + A[1][1]*y + A[2][1]*z) + z*(A[0][2]*x + A[1][2]*y + A[2][2]*z); double D=v*v-4*u*w+4*u; if (D<0) return 0; D=sqrt(D); *l0=(-v-D) / (2*u); *l1=(-v+D) / (2*u); return 1; }
/*traverse the stack and return the magnetic field*/ int mcmagnet_get_field(double x, double y, double z, double t, double *bx,double *by, double *bz, void *dummy){ mcmagnet_field_info *p=stack[0]; Coords in,loc,b,bsum={0,0,0},zero={0,0,0}; Rotation r; /*PROP_MAGNET takes care of transforming local "PROP" coordinates to lab system*/ in.x=x;in.y=y;in.z=z; int i=0,stat=1; p=stack[i]; *bx=0;*by=0;*bz=0; if (!p) return 0; //mcmagnet_print_stack(); //printf("getfield_(lab):_(xyz,t)=( %g %g %g %g )\n",x,y,z,t); while(p){ /*transform to the coordinate system of the particular magnetic function*/ loc=coords_sub(rot_apply(*(p->rot),in),*(p->pos)); stat=(p->func) (loc.x,loc.y,loc.z,t,&(b.x),&(b.y),&(b.z),p->data); /*check if the field function should be garbage collected*/ //printf("getfield_(loc):_(xyz,t)=( %g %g %g %g )\n",loc.x,loc.y,loc.z,t); if (stat){ /*transform to the lab system and add up. (resusing loc variable - to now contain the field in lab coords)*/ rot_transpose(*(p->rot),r); loc=rot_apply(r,b); bsum.x+=loc.x;bsum.y+=loc.y;bsum.z+=loc.z; //printf("Bs=(%g %g %g), B=(%g %g %g)\n",bsum.x,bsum.y,bsum.z,loc.x,loc.y,loc.z); } if (p->stop) break; p=stack[++i]; } /*we now have the magnetic field in lab coords in loc., transfer it back to caller*/ *bx=bsum.x; *by=bsum.y; *bz=bsum.z; return 1; }
/**************************************************************************** * void SimpleNumMagnetPrecession(double x, double y, double z, double t, * double vx, double vy, double vz, * double* sx, double* sy, double* sz, double dt) * *****************************************************************************/ void SimpleNumMagnetPrecession(double mc_pol_x, double mc_pol_y, double mc_pol_z, double mc_pol_time, double mc_pol_vx, double mc_pol_vy, double mc_pol_vz, double* mc_pol_sx, double* mc_pol_sy, double* mc_pol_sz, double mc_pol_deltaT, Coords mc_pol_posLM, Rotation mc_pol_rotLM) { double mc_pol_Bx, mc_pol_By, mc_pol_Bz, mc_pol_phiz; double mc_pol_BxStart, mc_pol_ByStart, mc_pol_BzStart, mc_pol_Bstart; double mc_pol_BxTemp, mc_pol_ByTemp, mc_pol_BzTemp, mc_pol_Btemp; double mc_pol_Bstep, mc_pol_timeStep, mc_pol_sp; const double mc_pol_spThreshold = cos(mc_pol_angular_accuracy); const double mc_pol_startTimeStep = mc_pol_initial_timestep; // s double dummy1, dummy2; Rotation mc_pol_rotBack; mcMagneticField=mcmagnet_get_field; //printf("pos_at_caller(xyz)( %g %g %g )\n", mc_pol_x,mc_pol_y,mc_pol_z); // change coordinates from current local system to lab system mccoordschange(mc_pol_posLM, mc_pol_rotLM, &mc_pol_x, &mc_pol_y, &mc_pol_z, &mc_pol_vx, &mc_pol_vy, &mc_pol_vz, mc_pol_sx, mc_pol_sy, mc_pol_sz); //printf("pos_at_labaftertranformation(xyz)( %g %g %g )\n", mc_pol_x,mc_pol_y,mc_pol_z); // get initial B-field value mcMagneticField(mc_pol_x, mc_pol_y, mc_pol_z, mc_pol_time, &mc_pol_BxTemp, &mc_pol_ByTemp, &mc_pol_BzTemp,NULL); do { mc_pol_Bx = 0; mc_pol_By = 0; mc_pol_Bz = 0; mc_pol_phiz = 0; mc_pol_BxStart = mc_pol_BxTemp; mc_pol_ByStart = mc_pol_ByTemp; mc_pol_BzStart = mc_pol_BzTemp; mc_pol_Bstart = sqrt(mc_pol_BxStart*mc_pol_BxStart + mc_pol_ByStart*mc_pol_ByStart + mc_pol_BzStart*mc_pol_BzStart); mc_pol_timeStep = mc_pol_startTimeStep; if(mc_pol_deltaT<mc_pol_timeStep) mc_pol_timeStep = mc_pol_deltaT; do { mcMagneticField(mc_pol_x+mc_pol_vx*mc_pol_timeStep, mc_pol_y+mc_pol_vy*mc_pol_timeStep, mc_pol_z+mc_pol_vz*mc_pol_timeStep, mc_pol_time+mc_pol_timeStep, &mc_pol_BxTemp, &mc_pol_ByTemp, &mc_pol_BzTemp,NULL); // not so elegant, but this is how we make sure that the steps decrease // when the WHILE condition is not met mc_pol_timeStep *= 0.5; mc_pol_Btemp = sqrt(mc_pol_BxTemp*mc_pol_BxTemp + mc_pol_ByTemp*mc_pol_ByTemp + mc_pol_BzTemp*mc_pol_BzTemp); mc_pol_sp = scalar_prod(mc_pol_BxStart, mc_pol_ByStart, mc_pol_BzStart, mc_pol_BxTemp, mc_pol_ByTemp, mc_pol_BzTemp); mc_pol_sp /= mc_pol_Bstart*mc_pol_Btemp; } while (mc_pol_sp<mc_pol_spThreshold && mc_pol_timeStep>FLT_EPSILON); mc_pol_timeStep*=2; // update coordinate values mc_pol_x += mc_pol_vx*mc_pol_timeStep; mc_pol_y += mc_pol_vy*mc_pol_timeStep; mc_pol_z += mc_pol_vz*mc_pol_timeStep; mc_pol_time += mc_pol_timeStep; mc_pol_deltaT -= mc_pol_timeStep; mc_pol_Bx = 0.5 * (mc_pol_BxStart + mc_pol_BxTemp); mc_pol_By = 0.5 * (mc_pol_ByStart + mc_pol_ByTemp); mc_pol_Bz = 0.5 * (mc_pol_BzStart + mc_pol_BzTemp); mc_pol_phiz = fmod(sqrt(mc_pol_Bx*mc_pol_Bx+ mc_pol_By*mc_pol_By+ mc_pol_Bz*mc_pol_Bz) *mc_pol_timeStep*mc_pol_omegaL, 2*PI); // Do the neutron spin precession if(!(mc_pol_Bx==0 && mc_pol_By==0 && mc_pol_Bz==0)) { double mc_pol_sx_in = *mc_pol_sx; double mc_pol_sy_in = *mc_pol_sy; double mc_pol_sz_in = *mc_pol_sz; rotate(*mc_pol_sx, *mc_pol_sy, *mc_pol_sz, mc_pol_sx_in, mc_pol_sy_in, mc_pol_sz_in, mc_pol_phiz, mc_pol_Bx, mc_pol_By, mc_pol_Bz); } } while (mc_pol_deltaT>0); // change back spin coordinates from lab system to local system rot_transpose(mc_pol_rotLM, mc_pol_rotBack); mccoordschange_polarisation(mc_pol_rotBack, mc_pol_sx, mc_pol_sy, mc_pol_sz); }