/** * \brief * Computes Spherical Linear Interpolation (SLERP) between two unit vectors. * \details * Spherical linear interpolation (or slerping) is a method for smoothly * interpolating points on a sphere (its a spherical geometry version of * linear interpolation). Let \f$\hat{a}\f$ and \f$\hat{b}\f$ be units * vectors and \f$\phi\f$ be the angle between them. We can interpolate to * a fraction alpha through the rotation between them using the formula; * * \f[ \hat{z} = { \sin((1-\alpha)\phi)\over\sin(\phi)} \hat{a} + { * \sin(\alpha\phi)\over\sin(\phi)} \hat{b} \f] * * The routine Lgm_InitSlerp() finds \f$\sin(\phi)\f$ and \f$\phi\f$ given * the unbit vectors \f$\hat{a}\f$ and \f$\hat{b}\f$. Note that for small * values of \f$\phi\f$, the routine uses the approximation; * * \f[ \hat{z} = (1-\alpha) \hat{a} + \alpha \hat{b} \f]. * * * * \param[in] a: initial unit vector. * \param[in] b: final unit vector. * \param[in] z: interpolated unit vector. * \param[in] alpha: fraction of the angle phi to rotate to. * \param[in] si: Lgm_SlerpInfo structure. */ void Lgm_Slerp( Lgm_Vector *a, Lgm_Vector *b, Lgm_Vector *z, double alpha, Lgm_SlerpInfo *si ) { Lgm_Vector w1, w2; /* * Check to see that Phi is small. If it is, use approximation. */ if ( si->Phi < 1e-9 ) { w1 = *a; Lgm_ScaleVector( &w1, (1.0-alpha) ); w2 = *b; Lgm_ScaleVector( &w2, alpha ); } else { w1 = *a; Lgm_ScaleVector( &w1, sin( (1.0-alpha)*si->Phi )/ si->SinPhi ); w2 = *b; Lgm_ScaleVector( &w2, sin( alpha*si->Phi )/ si->SinPhi ); } Lgm_VecAdd( z, &w1, &w2 ); }
/** * \brief * Compute the instantaneous gradient and curvature drift velocity of the guiding center. * * * * \details * The gradient and curvature drift velocity of the guiding center is given by; * \f[ * V_s = {mv^2\over qB^2}\left(\left(1-{B\over * 2B_m}\right){\vec{B}\times\nabla B\over B} + \left(1-{B\over * B_m}\right){(\nabla\times \vec{B})_perp} \right) * \f] * (e.g. see Sukhtina, M.A., "One the calculation of the magnetic srift * velocity of particles with arbitrary pitch angles, Planet Space Sci. * 41, 327--331, 1993.) With \f$\eta = T/E_0\f$, where \f$T\f$ is the * particle's kinetic energy, and \f$E_0\f$ its rest energy, this can be * rewritten as, * \f[ * V_s = {\eta (2+\eta)\over (1+\eta)}{E_0\over qB^2}\left(\left(1-{B\over * 2B_m}\right){\vec{B}\times\nabla B\over B} + \left(1-{B\over * B_m}\right){(\nabla\times \vec{B})_perp} \right) * \f] * * * \param[in] u0 Position (in GSM) to use. [Re] * \param[out] Vel The computed drift velocity in GSM coords. [km/s] * \param[in] q Charge of the particle. [C] * \param[in] T Kinetic energy of the particle. [MeV] * \param[in] E0 Rest energy of the particle. [MeV] * \param[in] Bm Magnitude of B-field at mirror point for particle. [nT] * \param[in] DerivScheme Derivative scheme to use (can be one of LGM_DERIV_SIX_POINT, LGM_DERIV_FOUR_POINT, or LGM_DERIV_TWO_POINT). * \param[in] h The delta (in Re) to use for grid spacing in the derivative scheme. * \param[in,out] m A properly initialized and configured Lgm_MagModelInfo structure. * * * \author Mike Henderson * \date 2011 * */ int Lgm_GradAndCurvDriftVel( Lgm_Vector *u0, Lgm_Vector *Vel, Lgm_MagModelInfo *m ) { double B, BoverBm, g, eta, h, Beta, Beta2, Gamma; double q, T, E0, Bm; int DerivScheme; Lgm_Vector CurlB, CurlB_para, CurlB_perp, GradB, Bvec, Q, R, S, W, Z; Lgm_Vector B_Cross_GradB; q = m->Lgm_VelStep_q; T = m->Lgm_VelStep_T; E0 = m->Lgm_VelStep_E0; Bm = m->Lgm_VelStep_Bm; h = m->Lgm_VelStep_h; DerivScheme = m->Lgm_VelStep_DerivScheme; //printf("Lgm_GradAndCurvDriftVel: u0 = %g %g %g\n", u0->x, u0->y, u0->z); m->Bfield( u0, &Bvec, m ); B = Lgm_Magnitude( &Bvec ); BoverBm = B/Bm; //printf("BoverBm = %g\n", BoverBm); /* * Compute B cross GradB [nT/Re] */ Lgm_GradB( u0, &GradB, DerivScheme, h, m ); Lgm_CrossProduct( &Bvec, &GradB, &B_Cross_GradB ); /* * Compute (curl B)_perp [nT/Re] */ Lgm_CurlB2( u0, &CurlB, &CurlB_para, &CurlB_perp, DerivScheme, h, m ); /* * Compute instantaneous gradient/curv drift Velocity. */ Q = B_Cross_GradB; g = (1.0-0.5*BoverBm)/B; //printf("g1 = %g\n", g); Lgm_ScaleVector( &Q, g ); // [nT/Re] R = CurlB_perp; g = 1.0-BoverBm; //printf("g2 = %g\n", g); Lgm_ScaleVector( &R, g ); // [nT/Re] Lgm_VecAdd( &S, &Q, &R ); // [nT/Re] eta = T/E0; // kinetic energy over rest energy Gamma = eta + 1.0; Beta2 = 1.0 - 1.0/(Gamma*Gamma); Beta = sqrt( Beta2 ); g = Gamma*Beta2*E0*1e6*Joules_Per_eV/(q*B*B); // [ N m / (A s nT^2) ] // gS would have units of [ N m / (A s nT Re) ], so convert nT and Re to SI // to get a final answer in m/s. Then convert to km/s. g *= 1e9/(Re*1e6); g /= Re; //Re/s //printf("g3 = %g\n", g); Lgm_ScaleVector( &S, g ); // [ N m / (A s T m) ] = [ N m / (A s (N/(A m) m) ] = [ m/s ] // now its Re/s // Add in parallel velocity (Note that v = c*Beta) if (BoverBm >= 1.0) { g = 0.0; } else { g = -LGM_c/(1000.0*Re)*Beta*sqrt(1.0-BoverBm)/B; } //printf("T = %g, Beta = %g g = %g\n", T, Beta, g); W = Bvec; Lgm_ScaleVector( &W, g ); //printf("W = %g %g %g\n", W.x, W.y, W.z); Lgm_VecAdd( &Z, &S, &W ); *Vel = Z; return(1); }