double seFunc( Lgm_Vector *P, double TargetHeight, Lgm_MagModelInfo *Info ) { Lgm_Vector w; double Height, F; Height = WGS84_A*(Lgm_Magnitude( P )-1.0); F = Height - TargetHeight; return( F ); }
void Lgm_B_Cross_GradB_Over_B( Lgm_Vector *u0, Lgm_Vector *A, int DerivScheme, double h, Lgm_MagModelInfo *m ) { double B; Lgm_Vector GradB, Bvec; m->Bfield( u0, &Bvec, m ); B = Lgm_Magnitude( &Bvec ); Lgm_GradB( u0, &GradB, DerivScheme, h, m ); Lgm_CrossProduct( &Bvec, &GradB, A ); Lgm_ScaleVector( A, 1.0/B ); }
/** * \brief * Initialize a Lgm_SlerpInfo structure. * \details * This routine computes \f$\sin(\phi)\f$, \f$\cos(\phi)\f$, and * \f$\phi\f$. Where \f$\phi\f$ is the angle between the initial and final * unit vectors. This is done outside the main slerp routine because you * may want to perform many interps with the same endpoint vectors. * * \param[in] a: initial unit vector. * \param[in] b: final unit vector. * * \param[in,out] si: Lgm_SlerpInfo structure. * */ void Lgm_InitSlerp( Lgm_Vector *a, Lgm_Vector *b, Lgm_SlerpInfo *si ) { Lgm_Vector v, w; si->CosPhi = Lgm_DotProduct( a, b ); w = *a; Lgm_ScaleVector( &w, si->CosPhi ); // w = cos(phi)*a-hat Lgm_VecSub( &v, b, &w ); // v = b-hat - cos(phi)*a-hat si->SinPhi = Lgm_Magnitude( &v ); // sin(phi) si->Phi = atan2( si->SinPhi, si->CosPhi ); // Phi }
/* * Normalize the given vector. I.e. make it into a unit vector. * plus return magnitude since you already have it! */ double Lgm_NormalizeVector(Lgm_Vector *a) { double magnitude, inv; magnitude = Lgm_Magnitude(a); if (magnitude > 0.0) { inv = 1.0/magnitude; a->x *= inv; a->y *= inv; a->z *= inv; return(magnitude); } else { return(-1.0); } }
int main( ) { Lgm_ElapsedTimeInfo t; Lgm_CTrans *c = Lgm_init_ctrans( 1 ); // more compact declaration Lgm_QinDentonOne p; Lgm_MagModelInfo *mInfo; Lgm_Vector *u, *B, q, v; double Time, JD, x, y, z, r, d, dist; long int Date, n; Lgm_Octree *Octree; Lgm_OctreeData *kNN; int K, Kgot, i, j; t.ColorizeText = TRUE; Lgm_ElapsedTimeInit( &t, 255, 150, 0 ); LGM_ARRAY_1D( u, 5000000, Lgm_Vector ); LGM_ARRAY_1D( B, 5000000, Lgm_Vector ); mInfo = Lgm_InitMagInfo( ); Date = 20020713; // August 12, 2004 Time = 18.0 + 0.0/60.0 + 30.0/3600.0; // Universal Time Coordinated (in decimal hours) JD = Lgm_Date_to_JD( Date, Time, c ); // Compute JD // Get (interpolate) the QinDenton vals from the values in the file at the given Julian Date Lgm_get_QinDenton_at_JD( JD, &p, 0 ); Lgm_Set_Coord_Transforms( Date, Time, mInfo->c ); Lgm_set_QinDenton( &p, mInfo ); mInfo->Bfield = Lgm_B_T89; d = 0.3; n = 0; Lgm_PrintCurrentTime( &t ); for ( x = -15.0; x <= 15.0; x += d ){ for ( y = -15.0; y <= 15.0; y += d ){ for ( z = -15.0; z <= 15.0; z += d ){ u[n].x = x; u[n].y = y; u[n].z = z; r = Lgm_Magnitude( &u[n] ); //if (r > 1.1){ // mInfo->Bfield( &u[n], &B[n], mInfo ); ++n; //} } } } Lgm_PrintElapsedTime( &t ); printf("n = %ld\n", n); /* * Test kNN algorithm. */ printf("Creating Octree\n"); Lgm_ElapsedTimeInit( &t, 255, 150, 0 ); Octree = Lgm_InitOctree( u, B, n ); printf("Min, Max, Diff = %g %g %g\n", Octree->Min, Octree->Max, Octree->Diff); Lgm_PrintElapsedTime( &t ); q.x = 3.2233; q.y = 2.4698; q.z = 1.35193; K = 4; LGM_ARRAY_1D( kNN, K, Lgm_OctreeData ); printf("\n\nTesting kNN (1000000 times)\n"); Lgm_ElapsedTimeInit( &t, 255, 150, 0 ); for (j=0; j<=1000000; j++){ q.x = 30.0*rand()/(double)RAND_MAX - 15.0; q.y = 30.0*rand()/(double)RAND_MAX - 15.0; q.z = 30.0*rand()/(double)RAND_MAX - 15.0; Lgm_Octree_kNN( &q, Octree, K, &Kgot, 1.0*1.0, kNN ); } Lgm_PrintElapsedTime( &t ); printf("\n\nKgot = %d q = %g %g %g\n", Kgot, q.x, q.y, q.z); for (i=0; i<Kgot; i++){ Lgm_OctreeUnScalePosition( &(kNN[i].Position), &v, Octree ); Lgm_OctreeUnScaleDistance( sqrt(kNN[i].Dist2), &dist, Octree ); printf("%02d: dist = %g v = %g %g %g\n", i, dist, v.x, v.y, v.z ); } LGM_ARRAY_1D_FREE( kNN ); printf("Freeing Octree\n"); Lgm_ElapsedTimeInit( &t, 255, 150, 0 ); Lgm_FreeOctree( Octree ); printf("Octree Freed\n"); Lgm_PrintElapsedTime( &t ); Lgm_free_ctrans( c ); Lgm_FreeMagInfo( mInfo ); LGM_ARRAY_1D_FREE( u ); LGM_ARRAY_1D_FREE( B ); return(0); }
/* * Print an Lgm_Vector */ void Lgm_PrintVector(Lgm_Vector *v) { printf("x:%lf y:%lf z:%lf mag:%lf\n", v->x, v->y, v->z, Lgm_Magnitude(v)); return; }
/* * Find Magnitude of difference between to vectors */ double Lgm_VecDiffMag(Lgm_Vector *a, Lgm_Vector *b ) { Lgm_Vector c; Lgm_VecSub( &c, a, b ); // c = a-b return( Lgm_Magnitude( &c ) ); }
/** * \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); }
/** * Input Variables: * * Date: * UTC: * u: Input position vector in GSM * nAlpha: Number of Pitch Angles to compute * Alpha: Pitch Angles to compute * * Input/OutPut Variables: * * MagEphemInfo: Structure used to input and output parameters/settings/results to/from routine. * */ void Lgm_ComputeLstarVersusPA( long int Date, double UTC, Lgm_Vector *u, int nAlpha, double *Alpha, int Colorize, Lgm_MagEphemInfo *MagEphemInfo ) { Lgm_LstarInfo *LstarInfo, *LstarInfo2, *LstarInfo3; Lgm_Vector v1, v2, v3, vv1, Bvec; double sa, sa2, Blocal; double Lam, CosLam, LSimple; int i, k, LS_Flag, nn, tk, TraceFlag; char *PreStr, *PostStr; /* These should be set by the user in the setup up MagEphemInfo no in here */ //MagEphemInfo->LstarInfo->SaveShellLines = FALSE; //MagEphemInfo->LstarInfo->FindShellPmin = FALSE; //MagEphemInfo->LstarInfo->ComputeVgc = FALSE; //MagEphemInfo->LstarInfo->ComputeVgc = FALSE; LstarInfo = MagEphemInfo->LstarInfo; // Save Date, UTC to MagEphemInfo structure MagEphemInfo->Date = Date; MagEphemInfo->UTC = UTC; // Save nAlpha, and Alpha array to MagEphemInfo structure MagEphemInfo->nAlpha = nAlpha; for (i=0; i<MagEphemInfo->nAlpha; i++) MagEphemInfo->Alpha[i] = Alpha[i]; // Set Tolerances Lgm_SetLstarTolerances( MagEphemInfo->LstarQuality, MagEphemInfo->nFLsInDriftShell, LstarInfo ); // set coord transformation Lgm_Set_Coord_Transforms( Date, UTC, LstarInfo->mInfo->c ); /* * Blocal at sat location. */ MagEphemInfo->P = *u; LstarInfo->mInfo->Bfield( u, &Bvec, LstarInfo->mInfo ); Blocal = Lgm_Magnitude( &Bvec ); MagEphemInfo->B = Blocal; //printf("Blocal = %g\n", Blocal); for ( i=0; i<MagEphemInfo->nAlpha; i++ ){ sa = sin( MagEphemInfo->Alpha[i]*RadPerDeg ); sa2 = sa*sa; MagEphemInfo->Bm[i] = Blocal/sa2; //printf("Bm[%d] = %g\n", i, MagEphemInfo->Bm[i] ); } /* * Compute Field-related quantities for each Pitch Angle. * * * First do a trace to identify the FL type and some of its critical points. * */ TraceFlag = Lgm_Trace( u, &v1, &v2, &v3, LstarInfo->mInfo->Lgm_LossConeHeight, TRACE_TOL, TRACE_TOL2, LstarInfo->mInfo ); MagEphemInfo->FieldLineType = TraceFlag; //printf("P = %g %g %g Blocal = %lf Bmin = %lf \n", u->x, u->y, u->z, Blocal, MagEphemInfo->Bmin ); if ( TraceFlag > 0 ) { MagEphemInfo->Ellipsoid_Footprint_Ps = v1; MagEphemInfo->Ellipsoid_Footprint_Pn = v2; MagEphemInfo->Pmin = v3; MagEphemInfo->Snorth = LstarInfo->mInfo->Snorth; MagEphemInfo->Ssouth = LstarInfo->mInfo->Ssouth; MagEphemInfo->Smin = LstarInfo->mInfo->Smin; MagEphemInfo->Bmin = LstarInfo->mInfo->Bmin; //printf("P = %g %g %g Blocal = %lf Bmin = %lf \n", u->x, u->y, u->z, Blocal, MagEphemInfo->Bmin ); //MagEphemInfo->Mref = LstarInfo->mInfo->c->M_cd_McIllwain; MagEphemInfo->Mref = LstarInfo->mInfo->c->M_cd_2010; MagEphemInfo->Mcurr = LstarInfo->mInfo->c->M_cd; MagEphemInfo->Mused = MagEphemInfo->Mref; } if ( TraceFlag != 1 ) { /* * FL not closed. */ for ( i=0; i<MagEphemInfo->nAlpha; i++ ){ MagEphemInfo->Lstar[i] = LGM_FILL_VALUE; MagEphemInfo->I[i] = LGM_FILL_VALUE; MagEphemInfo->K[i] = LGM_FILL_VALUE; MagEphemInfo->Sb[i] = LGM_FILL_VALUE; } MagEphemInfo->Sb0 = LGM_FILL_VALUE; MagEphemInfo->d2B_ds2 = LGM_FILL_VALUE; MagEphemInfo->RofC = LGM_FILL_VALUE; } if ( TraceFlag == 1 ) { MagEphemInfo->Sb0 = LstarInfo->mInfo->Sb0; // Sb Integral for equatorially mirroring particles. MagEphemInfo->d2B_ds2 = LstarInfo->mInfo->d2B_ds2; // second deriv of B wrt s at equator. MagEphemInfo->RofC = LstarInfo->mInfo->RofC; // radius of curvature at Bmin point. /* * Get a simple measure of how big L is */ Lgm_Convert_Coords( &v1, &vv1, GSM_TO_SM, LstarInfo->mInfo->c ); Lam = asin( vv1.z/Lgm_Magnitude( &vv1 ) ); CosLam = cos( Lam ); //LSimple = (1.0+LstarInfo->mInfo->Lgm_LossConeHeight/WGS84_A)/( CosLam*CosLam ); LSimple = Lgm_Magnitude( &LstarInfo->mInfo->Pmin ); { // ***** BEGIN PARALLEL EXECUTION ***** /* * Do all of the PAs in parallel. To control how many threads get run * use the enironment variable OMP_NUM_THREADS. For example, * setenv OMP_NUM_THREADS 8 * will use 8 threads to do the loop in parallel. Be very careful what gets * set private here -- the threads must not interfere with each other. */ #if USE_OPENMP #pragma omp parallel private(LstarInfo2,LstarInfo3,sa,sa2,LS_Flag,nn,tk,PreStr,PostStr) #pragma omp for schedule(dynamic, 1) #endif for ( i=0; i<MagEphemInfo->nAlpha; i++ ){ // LOOP OVER PITCH ANGLES /* * make a local copy of LstarInfo structure -- needed for multi-threading */ LstarInfo3 = Lgm_CopyLstarInfo( LstarInfo ); /* * colorize the diagnostic messages. */ if ( Colorize ){ sprintf( LstarInfo3->PreStr, "\033[38;5;%dm", Colors[i%9]); sprintf( LstarInfo3->PostStr, "\033[0m"); } else { LstarInfo3->PreStr[0] = '\0'; LstarInfo3->PostStr[0] = '\0'; } PreStr = LstarInfo3->PreStr; PostStr = LstarInfo3->PostStr; /* * Set Bmirror */ LstarInfo3->mInfo->Bm = MagEphemInfo->Bm[i]; NewTimeLstarInfo( Date, UTC, MagEphemInfo->Alpha[i], LstarInfo3->mInfo->Bfield, LstarInfo3 ); /* * Compute L* */ if ( LSimple < LstarInfo3->LSimpleMax ){ LstarInfo2 = Lgm_CopyLstarInfo( LstarInfo3 ); LstarInfo2->mInfo->Bm = LstarInfo3->mInfo->Bm; if (LstarInfo3->VerbosityLevel >= 2 ) { printf("\n\n\t\t%sComputing L* for: UTC = %g (Local) PA = %d (%g)%s\n", PreStr, UTC, i, MagEphemInfo->Alpha[i], PostStr ); //printf(" \t\t%s I = %g PA = %d (%g)%s\n", PreStr, MagEphemInfo->I[i], i, MagEphemInfo->Alpha[i], PostStr ); } //////////////////////////////NOTE //////////////////////////////NOTE We are giving Lstar the Min B point ALREADY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //////////////////////////////NOTE //////////////////////////////NOTE //////////////////////////////NOTE //printf("LstarInfo2->mInfo->Bm = %g\n", LstarInfo2->mInfo->Bm); LS_Flag = Lstar( &v3, LstarInfo2); if (LstarInfo3->VerbosityLevel >= 2 ) { printf("\t\t%sUTC, L* = %g %g%s\n", PreStr, UTC, LstarInfo2->LS, PostStr ); printf("\t\t%sUTC, L*_McIlwain = %g %g%s\n", PreStr, UTC, LstarInfo2->LS_McIlwain_M, PostStr ); printf("\t\t%sUTC, LSimple = %g %g%s\n\n\n", PreStr, UTC, LSimple, PostStr ); } MagEphemInfo->Lstar[i] = ( LS_Flag >= 0 ) ? LstarInfo2->LS : LGM_FILL_VALUE; MagEphemInfo->I[i] = LstarInfo2->I[0]; // I[0] is I for the FL that the sat is on. MagEphemInfo->K[i] = LstarInfo2->I[0]*sqrt(MagEphemInfo->Bm[i]*1e-5); // Second invariant MagEphemInfo->Sb[i] = LstarInfo2->SbIntegral0; // SbIntegral0 is Sb for the FL that the sat is on. /* * Determine the type of the orbit */ if ( LS_Flag >= 0 ) { LstarInfo2->DriftOrbitType = LGM_DRIFT_ORBIT_CLOSED; for ( k=0; k<LstarInfo2->nMinMax; ++k ) { if ( LstarInfo2->nMinima[k] > 1 ) LstarInfo2->DriftOrbitType = LGM_DRIFT_ORBIT_CLOSED_SHABANSKY; } } else { LstarInfo2->DriftOrbitType = LGM_DRIFT_ORBIT_OPEN; for ( k=0; k<LstarInfo2->nMinMax; ++k ) { if ( LstarInfo2->nMinima[k] > 1 ) LstarInfo2->DriftOrbitType = LGM_DRIFT_ORBIT_OPEN_SHABANSKY; } } MagEphemInfo->DriftOrbitType[i] = LstarInfo2->DriftOrbitType; //printf("\t %sL* [ %g Deg. ]: Date: %ld UTC: %g Lsimple:%g L*:%.15g%s\n", PreStr, MagEphemInfo->Alpha[i], Date, UTC, LSimple, LstarInfo2->LS, PostStr ); if (LstarInfo3->VerbosityLevel > 0 ) { printf("\t %sL* [ %g\u00b0 ]: Date: %ld UTC: %g Lsimple:%g L*:%.15g%s\n", PreStr, MagEphemInfo->Alpha[i], Date, UTC, LSimple, LstarInfo2->LS, PostStr ); } /* * Save detailed results to the MagEphemInfo structure. */ MagEphemInfo->nShellPoints[i] = LstarInfo2->nPnts; for (nn=0; nn<LstarInfo2->nPnts; nn++ ){ MagEphemInfo->Shell_Pmin[i][nn] = LstarInfo2->Pmin[nn]; MagEphemInfo->Shell_Bmin[i][nn] = LstarInfo2->Bmin[nn]; MagEphemInfo->Shell_GradI[i][nn] = LstarInfo2->GradI[nn]; MagEphemInfo->Shell_Vgc[i][nn] = LstarInfo2->Vgc[nn]; MagEphemInfo->ShellI[i][nn] = LstarInfo2->I[nn]; MagEphemInfo->ShellSphericalFootprint_Pn[i][nn] = LstarInfo2->Spherical_Footprint_Pn[nn]; MagEphemInfo->ShellSphericalFootprint_Sn[i][nn] = LstarInfo2->Spherical_Footprint_Sn[nn]; MagEphemInfo->ShellSphericalFootprint_Bn[i][nn] = LstarInfo2->Spherical_Footprint_Bn[nn]; MagEphemInfo->ShellSphericalFootprint_Ps[i][nn] = LstarInfo2->Spherical_Footprint_Ps[nn]; MagEphemInfo->ShellSphericalFootprint_Ss[i][nn] = LstarInfo2->Spherical_Footprint_Ss[nn]; MagEphemInfo->ShellSphericalFootprint_Bs[i][nn] = LstarInfo2->Spherical_Footprint_Bs[nn]; MagEphemInfo->ShellEllipsoidFootprint_Pn[i][nn] = LstarInfo2->Ellipsoid_Footprint_Pn[nn]; MagEphemInfo->ShellEllipsoidFootprint_Sn[i][nn] = LstarInfo2->Ellipsoid_Footprint_Sn[nn]; MagEphemInfo->ShellEllipsoidFootprint_Bn[i][nn] = LstarInfo2->Ellipsoid_Footprint_Bn[nn]; MagEphemInfo->ShellEllipsoidFootprint_Ps[i][nn] = LstarInfo2->Ellipsoid_Footprint_Ps[nn]; MagEphemInfo->ShellEllipsoidFootprint_Ss[i][nn] = LstarInfo2->Ellipsoid_Footprint_Ss[nn]; MagEphemInfo->ShellEllipsoidFootprint_Bs[i][nn] = LstarInfo2->Ellipsoid_Footprint_Bs[nn]; MagEphemInfo->ShellMirror_Pn[i][nn] = LstarInfo2->Mirror_Pn[nn]; //MagEphemInfo->ShellMirror_Sn[i][nn] = LstarInfo2->mInfo->Sm_North; MagEphemInfo->ShellMirror_Sn[i][nn] = LstarInfo2->Mirror_Sn[nn]; MagEphemInfo->ShellMirror_Ps[i][nn] = LstarInfo2->Mirror_Ps[nn]; //MagEphemInfo->ShellMirror_Ss[i][nn] = LstarInfo2->mInfo->Sm_South; MagEphemInfo->ShellMirror_Ss[i][nn] = LstarInfo2->Mirror_Ss[nn]; /* * Save all of the drift shell FLs in MagEphemInfo structure */ MagEphemInfo->nFieldPnts[i][nn] = LstarInfo2->nFieldPnts[nn]; for (tk=0; tk<LstarInfo2->nFieldPnts[nn]; tk++){ // loop over points in a FL MagEphemInfo->s_gsm[i][nn][tk] = LstarInfo2->s_gsm[nn][tk]; MagEphemInfo->Bmag[i][nn][tk] = LstarInfo2->Bmag[nn][tk]; MagEphemInfo->x_gsm[i][nn][tk] = LstarInfo2->x_gsm[nn][tk]; MagEphemInfo->y_gsm[i][nn][tk] = LstarInfo2->y_gsm[nn][tk]; MagEphemInfo->z_gsm[i][nn][tk] = LstarInfo2->z_gsm[nn][tk]; } //printf("LstarInfo2->nFieldPnts[%d] = %d\n", nn, LstarInfo2->nFieldPnts[nn]); MagEphemInfo->nMinima[i][nn] = LstarInfo2->nMinima[nn]; MagEphemInfo->nMaxima[i][nn] = LstarInfo2->nMaxima[nn]; } FreeLstarInfo( LstarInfo2 ); } else { printf(" Lsimple >= %g ( Not doing L* calculation )\n", LstarInfo3->LSimpleMax ); MagEphemInfo->Lstar[i] = LGM_FILL_VALUE; //printf("Bm = %g\n", MagEphemInfo->Bm[i]); MagEphemInfo->I[i] = LGM_FILL_VALUE; MagEphemInfo->K[i] = LGM_FILL_VALUE; MagEphemInfo->nShellPoints[i] = 0; } FreeLstarInfo( LstarInfo3 ); } } // ***** END PARALLEL EXECUTION ***** } return; }
int Lgm_TraceToSphericalEarth( Lgm_Vector *u, Lgm_Vector *v, double TargetHeight, double sgn, double tol, Lgm_MagModelInfo *Info ) { Lgm_Vector u_scale; double Htry, Htry_max, Hdid, Hnext, Hmin, Hmax, s; double Sa=0.0, Sc=0.0, d; double Rinitial, Fa, Fb, Fc, F; double Height, StartHeight; double Height_a, Height_b, Height_c, HeightPlus, HeightMinus, direction; Lgm_Vector Pa, Pc, P; int done, reset, AboveTargetHeight, Count; reset = TRUE; Info->Trace_s = 0.0; Sa = Sc = 0.0; /* * Determine our initial geocentric radius in km. (u is assumed to be in * units of Re where we define Re to be WGS84_A.) */ Rinitial = WGS84_A*Lgm_Magnitude( u ); // km /* * The Earth is a spheroid. It is more flattened at the poles than at the * equator. Check to see if we are initially at a height where we need to * worry about it. For WGS84 Earth shape model, the equatorial radius is * WGS84_A and polar radius is WGS84_B (WGS84_B is about 20km smaller than * WGS84_A). * * Note that although we are trying to trace to a spherical Earth in this * routine, we still dont want to drop below the surface of the real Earth * (IGRF doesnt like that so much). * */ if ( Rinitial < WGS84_B ) { // must be inside the Earth, which is no good -- bail with // LGM_INSIDE_EARTH error code return( LGM_INSIDE_EARTH ); } else { // We are at least at or above WGS84_B. We could still be in trouble in // terms of being inside the Earth, so we have to check more // thouroughly now. Determine Geodetic Height Lgm_WGS84_to_GeodHeight( u, &Height ); if ( Height < 0.0 ) { // inside the Earth, which is no good -- bail with error return( LGM_INSIDE_EARTH ); } } /* * If we get here, the initial point must be above the surface of the * (spheroidal) Earth. * * Now check to see if we are currently above or below the target height. * (reset Height to be distance in km above the spherical approx of the Earth.) */ Height = Rinitial - WGS84_A; // distance above spherical Earth AboveTargetHeight = ( Height > TargetHeight ) ? TRUE : FALSE; /* * Initialize some things */ Pa.x = Pa.y = Pa.z = 0.0; Pc.x = Pc.y = Pc.z = 0.0; P = *u; Hmax = Info->Hmax; Hmax = 1.0; Hmin = 0.001; Hmin = 1e-8; u_scale.x = u_scale.y = u_scale.z = 1.0; Height = Height_a = Height_b = Height_c = 0.0; F = Fa = Fb = Fc = 0.0; //printf("\nHmax = %g\n", Hmax); /* * Save initial point if we need to */ if (Info->SavePoints) fprintf(Info->fp, "%f \t%f\t %f\t 3\n", u->x, u->y, u->z); /* * If we are above the target height, a potential problem will occur if the * field line is open in the direction of tracing. Fortunately, that * situation is easy to detect and is taken care of later... * * Here we need to test for and deal with the opposite problem. If we are * already below the target height, it is possible that the field line * never gets high enough to reach the target height. This is more tricky * to deal with because we can run the risk of getting below the surface of * the Earth. We need to try to get back above the target height to test * for this. If we cannot get above we need to bail out of the routine * altogether. */ StartHeight = Height; if ( !AboveTargetHeight ) { /* * Determine which direction along the field line will take us higher. */ Htry = 0.001; // sgn = +1 P = *u; if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, 1.0, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); HeightPlus = WGS84_A*(Lgm_Magnitude( &P )-1.0); // sgn = -1 P = *u; if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, -1.0, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); HeightMinus = WGS84_A*(Lgm_Magnitude( &P )-1.0); direction = ( HeightPlus > HeightMinus ) ? 1.0 : -1.0; /* * We are already at or below target height. Trace until we are not. */ done = FALSE; //reset = TRUE; while ( !done ) { Htry = fabs(0.9*(TargetHeight - Height)); // This computes Htry as 90% of the distance to the TargetHeight if (Htry > 0.1) Htry = 0.1; // If its bigger than 0.1 reset it to 0.1 -- to be safe. if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, direction, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); //printf("1. PPPPPPPPPP = %g %g %g\n", P.x, P.y, P.z); Sa += Hdid; Info->Trace_s += Hdid; Height = WGS84_A*(Lgm_Magnitude( &P )-1.0); F = Height - TargetHeight; if ( F > 0.0 ) { done = TRUE; } else if ( Height < StartHeight ) { // We are going back down again -- Target Height unreachable? -- Bail out return( LGM_TARGET_HEIGHT_UNREACHABLE ); } } } /* * Bracket the zero first. * We want to stop in the ionosphere at a certain height above the Earth * (assumed to be a spehere of radius WGS84_A in this routine). We need * to find 2 points along the field line such that the intersection of the * FL with the sphere is guaranteed to lie between them. To do this, we * need to find two points; Pa and Pc such that; * * and Height( Pa ) - TargetHeight > 0.0 * and Height( Pc ) - TargetHeight < 0.0 * * I.e., F = Height - TargetHeight has opposite signs * * Set the start point, Pa and Fa. (Fa is difference between Height_a and * TargetHeight.) * */ Pa = P; Height_a = WGS84_A*(Lgm_Magnitude( &Pa )-1.0); Fa = Height_a - TargetHeight; /* * Get an initial Htry that is safe -- i.e. start off slowly * We dont really know where we are, so be conservative on the first try. * If if ( Lgm_MagStep() gives back an Hnext thats higher, we'll crank Htry up then... */ Htry = 0.9*Height_a; // This computes Htry as 90% of the distance to the Earth's surface (could be small if we are already close!) if (Htry > Hmax) Htry = Hmax; // If its bigger than Hmax reset it to Hmax -- to be safe. /* * Keep stepping along the field line until we drop below the target * height, TargetHeight. (Or bail if its open). This completes the endpoints of the * bracket pair. We get these points first, because there are field lines * that have more than one local minimum in fabs(Height-TargetHeight). So find Pa and Pc * first and then complete the triple later. CHECK on this. I changed this * from a minima search to a simple root finder. Is it OK still? */ P = Pa; done = FALSE; //reset = TRUE; Count = 0; while ( !done ) { if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, sgn, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); Height = WGS84_A*(Lgm_Magnitude( &P )-1.0); //Lgm_Vector BBBBB; //Info->Bfield( &P, &BBBBB, Info ); //printf("2. PPPPPPPPPP = %g %g %g BBBBBBBBBB = %g %g %g Height = %g HTRY = %g HDID = %g HNEXT = %g\n", P.x, P.y, P.z, BBBBB.x, BBBBB.y, BBBBB.z, Height, Htry, Hdid, Hnext); F = Height - TargetHeight; if ((F > 0.0) && (Info->SavePoints)) fprintf(Info->fp, "%f \t%f\t %f\t 2\n", P.x, P.y, P.z); if ( (P.x > Info->OpenLimit_xMax) || (P.x < Info->OpenLimit_xMin) || (P.y > Info->OpenLimit_yMax) || (P.y < Info->OpenLimit_yMin) || (P.z > Info->OpenLimit_zMax) || (P.z < Info->OpenLimit_zMin) || ( s > 1000.0 ) ) { /* * Open FL! */ v->x = v->y = v->z = 0.0; return(0); } else if ( F < 0.0 ) { done = TRUE; Pc = P; Fc = F; Height_c = Height; //Sc += Hdid; Sc = Sa + Hdid; } else { Pa = P; Fa = F; Height_a = Height; Sa += Hdid; } //if ( fabs(Hdid-Htry) > 1e-6 ) Htry = Hnext; // adaptively reset Htry Htry = Hnext; // adaptively reset Htry //printf("A. Htry = %g\n", Htry); /* * Go no farther than some small distance below * the target Height. Also respect Hmin and Hmax. */ Htry_max = 0.9*Height; if (Htry > Htry_max) Htry = Htry_max; //printf("B. Htry = %g Htry, Hmin, Hmax, Htry_max = %g %g %g %g\n", Htry, Htry, Hmin, Hmax, Htry_max); if (Htry < Hmin) Htry = Hmin; else if (Htry > Hmax) Htry = Hmax; //printf("C. Htry = %g\n", Htry); if ( Count > 1000) { printf("File: %s Lgm_TraceToSphericalEarth(), Line: %d; Too many iterations trying to reach target height (are we in a weird field region?) Returning with -1.\n", __FILE__, __LINE__ ); //exit(0); return(-1); } ++Count; } if ( ((Fc > 0.0) && (Fa > 0.0)) || ((Fc < 0.0) && (Fa < 0.0)) ) { // No bracket return(0); } /* * We have a bracket. Now go in for the kill. * * (Note: If all we wanted to know is whether or not the line hits the * TargetHeight, we could stop here: it must or we wouldnt have a minimum * bracketed.) * * Use golden-section search to converge toward minimum. * (Sa, Sb, Sc) are the distances of the triple points along * the FL. For convenience, we maintain Sa = 0.0, so that * Sb and Sc are always the distances relative to Pa. (And * so Sc is always the width of the bracketed interval. So when * Sc gets small enough we bail out and take Pb as the min). * */ //reset = TRUE; if (1==1) { done = FALSE; while (!done) { d = Sc - Sa; //if ( fabs(F) < tol ) { if ( fabs(d) < tol ) { done = TRUE; } else { P = Pa; //Htry = LGM_1M_1O_GOLD*d; // LGM_1M_1O_GOLD is 0.381966... // if ( Htry > 2.0*fabs(F) ) { //Htry = LGM_1M_1O_GOLD*d; // LGM_1M_1O_GOLD is 0.381966... Htry = 0.5*fabs(d); // LGM_1M_1O_GOLD is 0.381966... // } if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, sgn, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); //printf("3. PPPPPPPPPP = %g %g %g HTRY = %g\n", P.x, P.y, P.z, Htry); Height = WGS84_A*(Lgm_Magnitude( &P )-1.0); F = Height - TargetHeight; if ( F >= 0.0 ) { Pa = P; Fa = F; Sa += Hdid; } else { Pc = P; Fc = F; Sc = Sa + Hdid; } } } Info->Trace_s = Sa; /* * Take average as the final answer. */ v->x = 0.5*(Pa.x + Pc.x); v->y = 0.5*(Pa.y + Pc.y); v->z = 0.5*(Pa.z + Pc.z); //printf( "Lgm_TraceToSphericalEarth: v = %g %g %g\n", v->x, v->y, v->z); } if (0==1) { /* * Try Brent's method */ //printf("Sa, Sb = %g %g Fa, Fb = %g %g tol = %g\n", Sa, Sb, Fa, Fb, tol); double Sz, Fz; Lgm_Vector Pz; BrentFuncInfoP f; f.u_scale = u_scale; f.Htry = Htry; f.sgn = sgn; f.reset = reset; f.Info = Info; f.func = &seFunc; f.Val = TargetHeight; Lgm_zBrentP( Sa, Sc, Fa, Fc, Pa, Pc, &f, tol, &Sz, &Fz, &Pz ); Fc = Fz; Sc = Sz; Pc = Pz; //printf("Sa, Sb = %g %g Fa, Fb = %g %g tol = %g\n", Sa, Sb, Fa, Fb, tol); v->x = Pz.x; v->y = Pz.y; v->z = Pz.z; Info->Trace_s = Sz; } if (Info->SavePoints) fprintf(Info->fp, "%f \t%f\t %f\t 2\n", v->x, v->y, v->z); if ( Info->VerbosityLevel > 2 ) printf("Lgm_TraceToSphericalEarth(): Number of Bfield evaluations = %ld\n", Info->Lgm_nMagEvals ); return( 1 ); }
/** * \brief * Compute the gradient of B at a given point. * * \details * Computes \f$ \nabla B \f$. * * * \param[in] u0 Position (in GSM) to use. * \param[out] GradB The computed gradient of B at position u0. * \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 * */ void Lgm_GradB( Lgm_Vector *u0, Lgm_Vector *GradB, int DerivScheme, double h, Lgm_MagModelInfo *m ) { double B, H, fx[7], fy[7], fz[7]; int i, N; Lgm_Vector u, Bvec; /* * Select the derivative scheme to use. * f_0^(1) = 1/(60h) ( f_3 - 9f_2 + 45f_1 - 45f_-1 + 9f_-2 - f_-3 ) * See page 450 of CRC standard Math tables 28th edition. */ switch ( DerivScheme ) { case LGM_DERIV_SIX_POINT: N = 3; break; case LGM_DERIV_FOUR_POINT: N = 2; break; case LGM_DERIV_TWO_POINT: N = 1; break; } if (m->VerbosityLevel > 0) printf("\t\tLgm_GradB: Computing GradB with DerivScheme = %d, h = %g", DerivScheme, h); for (i=-N; i<=N; ++i){ if ( N != 0 ) { u = *u0; H = (double)i*h; u.x += H; m->Bfield( &u, &Bvec, m ); B = Lgm_Magnitude( &Bvec ); fx[i+N] = B; } } for (i=-N; i<=N; ++i){ if ( N != 0 ) { u = *u0; H = (double)i*h; u.y += H; m->Bfield( &u, &Bvec, m ); B = Lgm_Magnitude( &Bvec ); fy[i+N] = B; } } for (i=-N; i<=N; ++i){ if ( N != 0 ) { u = *u0; H = (double)i*h; u.z += H; m->Bfield( &u, &Bvec, m ); B = Lgm_Magnitude( &Bvec ); fz[i+N] = B; } } if (DerivScheme == LGM_DERIV_SIX_POINT){ GradB->x = (fx[6] - 9.0*fx[5] + 45.0*fx[4] - 45.0*fx[2] + 9.0*fx[1] - fx[0])/(60.0*h); GradB->y = (fy[6] - 9.0*fy[5] + 45.0*fy[4] - 45.0*fy[2] + 9.0*fy[1] - fy[0])/(60.0*h); GradB->z = (fz[6] - 9.0*fz[5] + 45.0*fz[4] - 45.0*fz[2] + 9.0*fz[1] - fz[0])/(60.0*h); } else if (DerivScheme == LGM_DERIV_FOUR_POINT){ GradB->x = (-fx[4] + 8.0*fx[3] - 8.0*fx[1] + fx[0])/(12.0*h); GradB->y = (-fy[4] + 8.0*fy[3] - 8.0*fy[1] + fy[0])/(12.0*h); GradB->z = (-fz[4] + 8.0*fz[3] - 8.0*fz[1] + fz[0])/(12.0*h); } else if (DerivScheme == LGM_DERIV_TWO_POINT){ GradB->x = (fx[2] - fx[0])/(2.0*h); GradB->y = (fy[2] - fy[0])/(2.0*h); GradB->z = (fz[2] - fz[0])/(2.0*h); } if (m->VerbosityLevel > 0) printf(" GradB = (%g %g %g)\n", GradB->x, GradB->y, GradB->z ); return; }
/* * Note: The variables that save our state in this (and other fundtions) are * not local static variables, but are contained in the Lgm_MagModelInfo * structure that the user passes to it. This allows the function to be * thread-safe and re-entrant. */ double I_integrand( double s, _qpInfo *qpInfo ) { Lgm_Vector Bvec; int reset=1, done, Count; double f, g, Hremaining, Hdone, H, Htry, Hdid, Hnext, sgn=1.0, sdid, B, dS; Lgm_MagModelInfo *mInfo; /* * Get pointer to our auxilliary data structure. */ mInfo = (Lgm_MagModelInfo *)qpInfo; mInfo->Lgm_I_integrand_u_scale.x = 10.0; mInfo->Lgm_I_integrand_u_scale.y = 1.0; mInfo->Lgm_I_integrand_u_scale.z = 10.0; if ( mInfo->Lgm_I_integrand_JumpMethod == LGM_RELATIVE_JUMP_METHOD ) { /* * Set starting point. If this is the first call for this integral, * set point to the lower limit. */ if ( mInfo->Lgm_I_integrand_FirstCall == TRUE ) { mInfo->Lgm_I_integrand_FirstCall = FALSE; mInfo->Lgm_I_integrand_P = mInfo->Pm_South; mInfo->Lgm_I_integrand_S = 0.0; dS = s; } else { dS = s - mInfo->Lgm_I_integrand_S; } if (dS < 0.0) { H = -dS; sgn = -1.0; // H is a positive qnty } else { H = dS; sgn = 1.0; } } else if ( mInfo->Lgm_I_integrand_JumpMethod == LGM_ABSOLUTE_JUMP_METHOD ) { /* * This strategy starts at start each time. Slower(?), but seems to * limit roundoff error from accumulating? The speed increase of the * relative method really depends on how far apart the s points are * that the integrator is picking. If they are bouncing all over the * place the relative method still does alot of tracing. */ if ( mInfo->Lgm_I_integrand_FirstCall == TRUE ) { mInfo->Lgm_I_integrand_FirstCall = FALSE; } mInfo->Lgm_I_integrand_P = mInfo->Pm_South; mInfo->Lgm_I_integrand_S = 0.0; H = s; sgn = 1.0; // H is a positive qnty } else { printf("I_integrand: Error, unknown Jump Method ( Lgm_I_integrand_JumpMethod = %d\n", mInfo->Lgm_I_integrand_JumpMethod ); exit(-1); } /* * Get B-field at the given value of s. Need to advance along field line * by an amount H. May need to do more than one call to get there... * Setting Htry to be H is an attempt to make the full jump in one call to * MagStep. For very precise calculations, the number of jumps we do here * seems to be fairly critical. Making two jumps (i.e. Htry = H/2) and * limiting Hmax to 0.5 Re seems to work pretty well (perhaps its because * symetry between mirror points?). Could still play with the max step * size of 0.5 -- maybe something a bit higher would work just as well and * be more efficient? */ done = FALSE; Count = 0; Htry = 0.5*H; Hdone = 0.0; reset = TRUE; if (Htry > 0.5) Htry = 0.5; if ( fabs(mInfo->Lgm_I_integrand_S-s) < 1e-12 ) done = TRUE; while ( !done ) { Lgm_MagStep( &mInfo->Lgm_I_integrand_P, &mInfo->Lgm_I_integrand_u_scale, Htry, &Hdid, &Hnext, sgn, &sdid, &reset, mInfo->Bfield, mInfo ); Hdone += Hdid; // positive qnty mInfo->Lgm_I_integrand_S += sgn*Hdid; Hremaining = H - Hdone; if ( Count > 1000 ) { printf("I_integrand: Warning, early return because Count > 1000. Ill-conditioned integrand?\n"); done = TRUE; } else if ( fabs(mInfo->Lgm_I_integrand_S-s) < 1e-12 ){ done = TRUE; } else { if ( Htry > Hremaining ) Htry = Hremaining; } ++Count; } mInfo->Bfield( &mInfo->Lgm_I_integrand_P, &Bvec, mInfo ); B = Lgm_Magnitude( &Bvec ); /* * Compute integrand, ( 1 - B/Bm ) ^ (1/2) Make sure 1-B/Bm is not * negative. If it is, assume its zero. (Note that sometimes (due to * round-off error) it could be very slightly negative). */ g = 1.0 - B/mInfo->Bm; f = (g > 0.0) ? sqrt( g ) : 0.0; ++mInfo->Lgm_n_I_integrand_Calls; return( f ); }
/* * Compute Gradient of I */ int Lgm_Grad_I( Lgm_Vector *v0, Lgm_Vector *GradI, Lgm_MagModelInfo *mInfo ) { Lgm_Vector u, Pa, Pb; double rat, H, h, a, b, SS, Sa, Sb, I, f[6], r; int i, N; /* * We want to compute the gradient of I at the point v0. * This requires 3 derivatives: one each in x, y and z directions. * We will try a fairly acurate difference scehme: * * f_0^(1) = 1/(60h) ( f_3 - 9f_2 + 45f_1 - 45f_-1 + 9f_-2 - f_-3 ) * See page 450 of CRC standard Math tables 28th edition. */ /* * Set h to a smallish value */ // h = 5e-2; h = 0.1; // h = 0.2; switch ( DIFF_SCHEME ) { case USE_SIX_POINT: N = 3; break; case USE_FOUR_POINT: N = 2; break; case USE_TWO_POINT: N = 1; break; } // User should set these? mInfo->Lgm_I_Integrator = DQAGS; mInfo->Lgm_I_Integrator_epsabs = 0.0; mInfo->Lgm_I_Integrator_epsrel = 1e-5; /* X-component */ mInfo->UseInterpRoutines = 1; if (mInfo->VerbosityLevel > 0) printf("\t\tComputing dIdx: h = %g\n", h); for (i=-N; i<=N; ++i){ if (i!=0) { // dont need the center value in our difference scheme u = *v0; H = (double)i*h; u.x += H; /* * Trace to southern mirror point */ if ( Lgm_TraceToMirrorPoint( &u, &Pa, &Sa, mInfo->Bm, -1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { /* * Trace to northern mirror point */ if ( Lgm_TraceToMirrorPoint( &Pa, &Pb, &SS, mInfo->Bm, 1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { r = Lgm_Magnitude( &Pb ); //mInfo->Hmax = SS/200.0; mInfo->Hmax = SS/(double)mInfo->nDivs; Lgm_TraceLine2( &Pa, &Pb, (r-1.0)*Re, 0.5*SS-mInfo->Hmax, 1.0, 1e-7, FALSE, mInfo ); ReplaceFirstPoint( 0.0, mInfo->Bm, &Pa, mInfo ); AddNewPoint( SS, mInfo->Bm, &Pb, mInfo ); InitSpline( mInfo ); mInfo->Lgm_I_integrand_S = 0.0; mInfo->Lgm_I_integrand_FirstCall = TRUE; mInfo->Lgm_n_I_integrand_Calls = 0; mInfo->Sm_South = 0.0; mInfo->Sm_North = SS; if ( SS <= 1e-5 ) { // if FL length is small, use an approx expression for I rat = mInfo->Bmin/mInfo->Bm; if ((1.0-rat) < 0.0) { I = 0.0; } else { // Eqn 2.66b in Roederer I = SS*sqrt(1.0 - rat); printf("HEREEEEEEEEEEEEEEEEEEEEEEe\n"); } } else { I = Iinv_interped( mInfo ); } if (mInfo->VerbosityLevel > 2) printf("I = %g Lgm_n_I_integrand_Calls = %d\n", I, mInfo->Lgm_n_I_integrand_Calls ); FreeSpline( mInfo ); } else { printf("\t\tMirror point below %g km in Southern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } } else { printf("\t\tMirror point below %g km in Northern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } f[i+N] = I; } } if (DIFF_SCHEME == USE_SIX_POINT){ GradI->x = (f[6] - 9.0*f[5] + 45.0*f[4] - 45.0*f[2] + 9.0*f[1] - f[0])/(60.0*h); } else if (DIFF_SCHEME == USE_FOUR_POINT){ GradI->x = (-f[4] + 8.0*f[3] - 8.0*f[1] + f[0])/(12.0*h); } else if (DIFF_SCHEME == USE_TWO_POINT){ GradI->x = (f[2] - f[0])/(2.0*h); } /* Y-component */ if (mInfo->VerbosityLevel > 0) printf("\t\tComputing dIdy: h = %g\n", h); for (i=-N; i<=N; ++i){ if (i!=0) { // dont need the center value in our difference scheme u = *v0; H = (double)i*h; u.y += H; /* * Trace to southern mirror point */ if ( Lgm_TraceToMirrorPoint( &u, &Pa, &Sa, mInfo->Bm, -1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { /* * Trace to northern mirror point */ if ( Lgm_TraceToMirrorPoint( &Pa, &Pb, &SS, mInfo->Bm, 1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { r = Lgm_Magnitude( &Pb ); //mInfo->Hmax = SS/200.0; mInfo->Hmax = SS/(double)mInfo->nDivs; Lgm_TraceLine2( &Pa, &Pb, (r-1.0)*Re, 0.5*SS-mInfo->Hmax, 1.0, 1e-7, FALSE, mInfo ); ReplaceFirstPoint( 0.0, mInfo->Bm, &Pa, mInfo ); AddNewPoint( SS, mInfo->Bm, &Pb, mInfo ); InitSpline( mInfo ); mInfo->Lgm_I_integrand_S = 0.0; mInfo->Lgm_I_integrand_FirstCall = TRUE; mInfo->Lgm_n_I_integrand_Calls = 0; mInfo->Sm_South = 0.0; mInfo->Sm_North = SS; if ( SS <= 1e-5 ) { // if FL length is small, use an approx expression for I rat = mInfo->Bmin/mInfo->Bm; if ((1.0-rat) < 0.0) { I = 0.0; } else { // Eqn 2.66b in Roederer I = SS*sqrt(1.0 - rat); } } else { I = Iinv_interped( mInfo ); } if (mInfo->VerbosityLevel > 2) printf("I = %g Lgm_n_I_integrand_Calls = %d\n", I, mInfo->Lgm_n_I_integrand_Calls ); FreeSpline( mInfo ); } else { printf("\t\tMirror point below %g km in Southern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } } else { printf("\t\tMirror point below %g km in Northern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } f[i+N] = I; } } if (DIFF_SCHEME == USE_SIX_POINT){ GradI->y = (f[6] - 9.0*f[5] + 45.0*f[4] - 45.0*f[2] + 9.0*f[1] - f[0])/(60.0*h); } else if (DIFF_SCHEME == USE_FOUR_POINT){ GradI->y = (-f[4] + 8.0*f[3] - 8.0*f[1] + f[0])/(12.0*h); } else if (DIFF_SCHEME == USE_TWO_POINT){ GradI->y = (f[2] - f[0])/(2.0*h); } /* Z-component */ if (mInfo->VerbosityLevel > 0) printf("\t\tComputing dIdz: h = %g\n", h); for (i=-N; i<=N; ++i){ if (i!=0) { // dont need the center value in our difference scheme u = *v0; H = (double)i*h; u.z += H; /* * Trace to southern mirror point */ if ( Lgm_TraceToMirrorPoint( &u, &Pa, &Sa, mInfo->Bm, -1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { /* * Trace to northern mirror point */ if ( Lgm_TraceToMirrorPoint( &Pa, &Pb, &SS, mInfo->Bm, 1.0, mInfo->Lgm_TraceToMirrorPoint_Tol, mInfo ) > 0 ) { r = Lgm_Magnitude( &Pb ); //mInfo->Hmax = SS/200.0; mInfo->Hmax = SS/(double)mInfo->nDivs; Lgm_TraceLine2( &Pa, &Pb, (r-1.0)*Re, 0.5*SS-mInfo->Hmax, 1.0, 1e-7, FALSE, mInfo ); ReplaceFirstPoint( 0.0, mInfo->Bm, &Pa, mInfo ); AddNewPoint( SS, mInfo->Bm, &Pb, mInfo ); InitSpline( mInfo ); mInfo->Lgm_I_integrand_S = 0.0; mInfo->Lgm_I_integrand_FirstCall = TRUE; mInfo->Lgm_n_I_integrand_Calls = 0; mInfo->Sm_South = 0.0; mInfo->Sm_North = SS; if ( SS <= 1e-5 ) { // if FL length is small, use an approx expression for I rat = mInfo->Bmin/mInfo->Bm; if ((1.0-rat) < 0.0) { I = 0.0; } else { // Eqn 2.66b in Roederer I = SS*sqrt(1.0 - rat); } } else { I = Iinv_interped( mInfo ); } if (mInfo->VerbosityLevel > 2) printf("I = %g Lgm_n_I_integrand_Calls = %d\n", I, mInfo->Lgm_n_I_integrand_Calls ); FreeSpline( mInfo ); } else { printf("\t\tMirror point below %g km in Southern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } } else { printf("\t\tMirror point below %g km in Northern Hemisphere\n", mInfo->Lgm_LossConeHeight); exit(0); } f[i+N] = I; } } if (DIFF_SCHEME == USE_SIX_POINT){ GradI->z = (f[6] - 9.0*f[5] + 45.0*f[4] - 45.0*f[2] + 9.0*f[1] - f[0])/(60.0*h); } else if (DIFF_SCHEME == USE_FOUR_POINT){ GradI->z = (-f[4] + 8.0*f[3] - 8.0*f[1] + f[0])/(12.0*h); } else if (DIFF_SCHEME == USE_TWO_POINT){ GradI->z = (f[2] - f[0])/(2.0*h); } return(0); }
/* * This version traces FLs from the Earth at the given MLT/mlat instead of trying to find the Bm radially out first. */ double ComputeI_FromMltMlat2( double Bm, double MLT, double mlat, double *r, double I0, Lgm_LstarInfo *LstarInfo ) { int reset=1, reset2, TraceFlag; double Bmin, I, Phi, cl, sl, rat, SS1, SS2, SS, Sn, Ss, Htry, Hdid, Hnext, Bs, Be, s, sgn; Lgm_Vector w, u, Pmirror1, Pmirror2, v1, v2, v3, Bvec, P, Ps, u_scale, Bvectmp, Ptmp; double stmp, Btmp; /* * First do a trace to identify the FL type and some of its critical points. */ *r = 1.0 + 100.0/Re; Phi = 15.0*(MLT-12.0)*RadPerDeg; cl = cos( mlat * RadPerDeg ); sl = sin( mlat * RadPerDeg ); w.x = (*r)*cl*cos(Phi); w.y = (*r)*cl*sin(Phi); w.z = (*r)*sl; Lgm_Convert_Coords( &w, &u, SM_TO_GSM, LstarInfo->mInfo->c ); printf("w = %g %g %g\n", w.x, w.y, w.z); TraceFlag = Lgm_Trace( &u, &v1, &v2, &v3, LstarInfo->mInfo->Lgm_LossConeHeight, 1e-6, 1e-8, LstarInfo->mInfo ); LstarInfo->mInfo->Bfield( &v3, &Bvec, LstarInfo->mInfo ); Bmin = Lgm_Magnitude( &Bvec ); printf("Got here\n"); if ( TraceFlag != LGM_CLOSED ) { if (LstarInfo->VerbosityLevel > 1){ printf( "\t\t\t> Field Line not closed\n" ); } return( 9e99 ); } else if ( Bmin <= Bm ) { /* * From the minimum B point, attempt to trace along the field to get the northern mirror point. */ P = v3; SS1 = 0.0; if ( Lgm_TraceToMirrorPoint( &P, &Pmirror1, &SS1, LstarInfo->mInfo->Bm, 1.0, LstarInfo->mInfo->Lgm_TraceToMirrorPoint_Tol, LstarInfo->mInfo ) > 0 ) { SS2 = 0.0; if ( Lgm_TraceToMirrorPoint( &P, &Pmirror2, &SS2, LstarInfo->mInfo->Bm, -1.0, LstarInfo->mInfo->Lgm_TraceToMirrorPoint_Tol, LstarInfo->mInfo ) > 0 ) { } else { if (LstarInfo->VerbosityLevel > 3){ printf( "\t\t\t> Unable to find southern mirror point\n" ); } return( 9e99 ); } // total distance between mirror point. SS = SS1 + SS2; // If its really small, just return 0.0 for I if ( fabs(SS) < 1e-7) { if (LstarInfo->VerbosityLevel > 3){ printf( "\t\t\t> Distance between mirror points is < 1e-7Re, Assuming I=0\n" ); } return( 0.0 ); } } else { if (LstarInfo->VerbosityLevel > 3){ printf( "\t\t\t> Unable to find northern mirror point\n" ); } return( 9e99 ); } /* * OK, we have both mirror points. LEts compute I */ I = 9e99; LstarInfo->mInfo->Hmax = 0.1; LstarInfo->mInfo->Hmax = SS/(double)LstarInfo->mInfo->nDivs; /* * This little section is attempting to solve an annoying * precision issue. If the distance over which we are trying * to trace is too small, too many sub-divisions (i.e. total * steps) will lead to a step size that is too small. We can * end up with the gridded FL points computed in * Lgm_TraceLine3() such that the distance, s of the final * point is very slightly less than we expect. This tries to * reduce the number of divisions to avoid this in cases where * the total distance to trace is very small. */ int nDivs; if ( SS/LstarInfo->mInfo->nDivs < 1e-6 ) { nDivs = SS/1e-6; if (nDivs < 10) nDivs = 10; } else { nDivs = LstarInfo->mInfo->nDivs; } if ( Lgm_TraceLine3( &(LstarInfo->mInfo->Pm_South), SS, nDivs, 1.0, 1e-7, FALSE, LstarInfo->mInfo ) < 0 ) return( 9e99 ); /* * Set the limits of integration. */ LstarInfo->mInfo->Sm_South = 0.0; LstarInfo->mInfo->Sm_North = SS; if ( InitSpline( LstarInfo->mInfo ) ) { /* * Do I integral with interped integrand. */ I = Iinv_interped( LstarInfo->mInfo ); if (LstarInfo->VerbosityLevel > 1) { printf("\t\t%s mlat: %13.6g I: %13.6g I0: %13.6g I-I0: %13.6g [Sa,Sb]: %.8g %.8g (nCalls = %d)%s\n", LstarInfo->PreStr, mlat, I, I0, I-I0, LstarInfo->mInfo->Sm_South, LstarInfo->mInfo->Sm_North, LstarInfo->mInfo->Lgm_n_I_integrand_Calls, LstarInfo->PostStr ); } FreeSpline( LstarInfo->mInfo ); } else { I = 9e99; } } else { if (LstarInfo->VerbosityLevel > 1){ printf( "\t\t\t> Field line min-B is greater than Bm. Bm = %g Bmin = %g\n", Bm, Bmin ); } return( 9e99 ); } return( I ); }
/* * Input Variables: * * Date: * UTC: * brac1: Radial distance for inner edge of search bracket * brac2: Radial distance for outer edge of search bracket * Alpha: Equatorial pitch angle to compute * Quality: Quality factor (0-8) * * Input/OutPut Variables: * K: K value for LCDS at given alpha * LstarInfo: LstarInfo structure to specify B-field model, store last valid Lstar, etc. * */ int LCDS( long int Date, double UTC, double brac1, double brac2, double MLT, double Alpha, double tol, int Quality, double *K, Lgm_LstarInfo *LstarInfo ) { Lgm_LstarInfo *LstarInfo_brac1, *LstarInfo_brac2, *LstarInfo_test; Lgm_Vector v1, v2, v3, LCDSv3, Bvec, Ptest, PtestSM, Pinner, PinnerSM, Pouter, PouterSM; double Blocal, Xtest, sa, sa2, LCDS; double nTtoG = 1.0e-5; int LS_Flag, nn, k, TFlag; int maxIter = 50; //Start by creating necessary structures... need an Lstar info for each bracket, plus test point. LstarInfo_brac1 = Lgm_CopyLstarInfo( LstarInfo ); LstarInfo_brac2 = Lgm_CopyLstarInfo( LstarInfo ); LstarInfo_test = Lgm_CopyLstarInfo( LstarInfo ); // Set Tolerances Lgm_SetLstarTolerances( Quality, 24, LstarInfo_brac1 ); Lgm_SetLstarTolerances( Quality, 24, LstarInfo_brac2 ); Lgm_SetLstarTolerances( Quality, 24, LstarInfo_test ); // set coord transformation Lgm_Set_Coord_Transforms( Date, UTC, LstarInfo_brac1->mInfo->c ); Lgm_Set_Coord_Transforms( Date, UTC, LstarInfo_brac2->mInfo->c ); Lgm_Set_Coord_Transforms( Date, UTC, LstarInfo_test->mInfo->c ); //Check for closed drift shell at brackets PinnerSM.x = brac1*cos(MLT); PinnerSM.y = brac1*sin(MLT); PinnerSM.z = 0.0; Lgm_Convert_Coords( &PinnerSM, &Pinner, SM_TO_GSM, LstarInfo_test->mInfo->c ); /* * Test inner bracket location. */ LstarInfo_brac1->mInfo->Bfield( &Pinner, &Bvec, LstarInfo_brac1->mInfo ); Blocal = Lgm_Magnitude( &Bvec ); sa = sin( LstarInfo->PitchAngle*RadPerDeg ); sa2 = sa*sa; //Trace to minimum-B if ( Lgm_Trace( &Pinner, &v1, &v2, &v3, 120.0, 0.01, TRACE_TOL, LstarInfo_brac1->mInfo ) == LGM_CLOSED ) { //Only continue if bracket 1 is closed FL //Get L* LstarInfo_brac1->mInfo->Bm = LstarInfo_brac1->mInfo->Bmin/sa2; LS_Flag = Lstar( &v3, LstarInfo_brac1); LCDS = LstarInfo_brac1->LS; *K = (LstarInfo_brac1->I0)*sqrt(Lgm_Magnitude(&LstarInfo_brac1->Bmin[0])); if (LstarInfo->VerbosityLevel > 1) printf("Found valid inner bracket. Pinner_GSM, Pmin_GSM = (%g, %g, %g), (%g, %g, %g)\n", Pinner.x, Pinner.y, Pinner.z, LstarInfo_brac1->mInfo->Pmin.x, LstarInfo_brac1->mInfo->Pmin.y, LstarInfo_brac1->mInfo->Pmin.z); } else { FreeLstarInfo( LstarInfo_brac1 ); FreeLstarInfo( LstarInfo_brac2 ); FreeLstarInfo( LstarInfo_test ); return(-8); //Inner bracket is bad - bail } /* * Test outer bracket location. */ PouterSM.x = brac2*cos(MLT); PouterSM.y = brac2*sin(MLT); PouterSM.z = 0.0; Lgm_Convert_Coords( &PouterSM, &Pouter, SM_TO_GSM, LstarInfo_test->mInfo->c ); LstarInfo_brac2->mInfo->Bfield( &Pouter, &Bvec, LstarInfo_brac2->mInfo ); Blocal = Lgm_Magnitude( &Bvec ); //Trace to minimum-B if ( Lgm_Trace( &Pouter, &v1, &v2, &v3, 120.0, 0.01, TRACE_TOL, LstarInfo_brac2->mInfo ) == LGM_CLOSED ) { //If bracket 2 is closed FL then check for undefined L*. If L* is defined, we have a problem //Get L* LstarInfo_brac2->mInfo->Bm = LstarInfo_brac2->mInfo->Bmin/sa2; LS_Flag = Lstar( &v3, LstarInfo_brac2); if (LstarInfo_brac2->LS != LGM_FILL_VALUE) { //move outer bracket out and try again PouterSM.x = 1.7*Lgm_Magnitude(&Pouter)*cos(MLT); PouterSM.y = 1.7*Lgm_Magnitude(&Pouter)*sin(MLT); PouterSM.z = 0.0; Lgm_Convert_Coords( &PouterSM, &Pouter, SM_TO_GSM, LstarInfo_test->mInfo->c ); if ( Lgm_Trace( &Pouter, &v1, &v2, &v3, 120.0, 0.01, TRACE_TOL, LstarInfo_brac2->mInfo ) == LGM_CLOSED ) { LS_Flag = Lstar( &v3, LstarInfo_brac2); if (LstarInfo_brac2->LS != LGM_FILL_VALUE) { FreeLstarInfo( LstarInfo_brac1 ); FreeLstarInfo( LstarInfo_brac2 ); FreeLstarInfo( LstarInfo_test ); return(-9); //Outer bracket is bad - bail } } } } if (LstarInfo->VerbosityLevel > 1) { printf("Found valid outer bracket. Pouter_GSM, Pmin_GSM = (%g, %g, %g), (%g, %g, %g)\n", Pouter.x, Pouter.y, Pouter.z, LstarInfo_brac2->mInfo->Pmin.x, LstarInfo_brac2->mInfo->Pmin.y, LstarInfo_brac2->mInfo->Pmin.z); } //if brackets are okay, we've moved on without changing anything except setting initial LCDS value as L* at inner bracket nn = 0; while (Lgm_Magnitude(&Pouter)-Lgm_Magnitude(&Pinner) > tol){ if (LstarInfo->VerbosityLevel > 1) printf("Current LCDS iteration, bracket width = %d, %g\n", nn, Lgm_Magnitude(&Pouter)-Lgm_Magnitude(&Pinner)); if (nn > maxIter) { printf("********* EXCEEDED MAXITER\n"); //free structures before returning FreeLstarInfo( LstarInfo_brac1 ); FreeLstarInfo( LstarInfo_brac2 ); FreeLstarInfo( LstarInfo_test ); return(-2); //reached max iterations without achieving tolerance - bail } Xtest = (Lgm_Magnitude(&Pinner) + (Lgm_Magnitude(&Pouter)-Lgm_Magnitude(&Pinner))/2.0); PtestSM.x = -1.0*Xtest*cos(MLT); PtestSM.y = -1.0*Xtest*sin(MLT); PtestSM.z = 0.0; Lgm_Convert_Coords( &PtestSM, &Ptest, SM_TO_GSM, LstarInfo_test->mInfo->c ); LstarInfo_test->mInfo->Bfield( &Ptest, &Bvec, LstarInfo_test->mInfo ); Blocal = Lgm_Magnitude( &Bvec ); //Trace to minimum-B TFlag = Lgm_Trace( &Ptest, &v1, &v2, &v3, 120.0, 0.01, TRACE_TOL, LstarInfo_test->mInfo ); if ( TFlag == LGM_CLOSED ) { //If test point is closed FL then check for undefined L*. //Get L* LstarInfo_test->mInfo->Bm = LstarInfo_test->mInfo->Bmin/sa2; LS_Flag = Lstar( &v3, LstarInfo_test); if ( (LS_Flag > 0) || (LstarInfo_test->LS != LGM_FILL_VALUE) ){ //Drift shell defined Pinner = Ptest; LCDSv3 = v3; LCDS = LstarInfo_test->LS; *K = (LstarInfo_test->I0)*sqrt(LstarInfo_test->mInfo->Bm*nTtoG); //Determine the type of the orbit LstarInfo_test->DriftOrbitType = LGM_DRIFT_ORBIT_CLOSED; for ( k=0; k<LstarInfo_test->nMinMax; ++k ) { if ( LstarInfo_test->nMinima[k] > 1 ) LstarInfo_test->DriftOrbitType = LGM_DRIFT_ORBIT_CLOSED_SHABANSKY; if ( LstarInfo_test->nMinima[k] < 1 ) {printf("Less than one minimum defined on field line: Exit due to impossibility."); exit(-1); } } if (LstarInfo->VerbosityLevel > 1) printf("Current LCDS, K, PtestSM is %g, %g, (%g, %g, %g)\n", LCDS, *K, PtestSM.x, PtestSM.y, PtestSM.z); LstarInfo->mInfo->Bm = LstarInfo_test->mInfo->Bm; LstarInfo->DriftOrbitType = LstarInfo_test->DriftOrbitType; } else { Pouter = Ptest; Lgm_Convert_Coords( &Ptest, &PtestSM, GSM_TO_SM, LstarInfo_test->mInfo->c ); printf("Failed DS trace at test point (%g %g %g GSM; %g %g %g SM; TFlag = %d), moving outer bracket to current location\n", Ptest.x, Ptest.y, Ptest.z, PtestSM.x, PtestSM.y, PtestSM.z, TFlag); } } else { //FL open -> drift shell open Lgm_Convert_Coords( &Ptest, &PtestSM, GSM_TO_SM, LstarInfo_test->mInfo->c ); printf("Failed FL trace at test point (%g %g %g GSM; %g %g %g SM; TFlag = %d), moving outer bracket to current location\n", Ptest.x, Ptest.y, Ptest.z, PtestSM.x, PtestSM.y, PtestSM.z, TFlag); Pouter = Ptest; } nn++; } if (LstarInfo->VerbosityLevel > 0) printf("Final LCDS, K is %g, %g. Eq. radius = %g \n", LCDS, *K, Lgm_Magnitude( &LCDSv3 )); LstarInfo->LS = LCDS; //free structures FreeLstarInfo( LstarInfo_brac1 ); FreeLstarInfo( LstarInfo_brac2 ); FreeLstarInfo( LstarInfo_test ); return(0); }
int Lgm_TraceToYZPlane( Lgm_Vector *u, Lgm_Vector *v, double Xtarget, double sgn0, double tol, Lgm_MagModelInfo *Info ) { Lgm_Vector u_scale; double Htry, Hdid, Hnext, Hmin, Hmax, s, sgn, fsgn0; double Sa, Sb, B, f, r2, z2, r3, L, R, hhh; double Stotal; Lgm_Vector Btmp; Lgm_Vector Pa, Pb, P; int done, reset=TRUE, bracketed=FALSE; long int Ntotal; //printf("\n\n\n***************************************\n"); Pb.x = Pb.y = Pb.z = 0.0; Hmax = 20.0; Hmin = 0.01; u_scale.x = 100.0; u_scale.y = 100.0; u_scale.z = 100.0; /* * Set the start point, Pa */ Pa = *u; f = Xtarget - Pa.x; fsgn0 = ( f<0.0) ? -1.0 : 1.0; Sa = 0.0; Stotal = 0.0; Ntotal = 0; /* * Choose a good step size to try. */ Lgm_Convert_Coords( &Pa, &P, GSM_TO_SM, Info->c ); R = Lgm_Magnitude( &Pa ); r2 = R*R; z2 = P.z*P.z; L = 9e99; if ( fabs( r2 - z2 ) < 1e-2 ) { /* * High L */ Htry = 2.0; } else { r3 = r2*R; L = r3 / (r2 - z2); Htry = ( L < 4.5 ) ? 1.165*L : 4.5; } if ( Htry < 1e-4 ) Htry = 0.001; //Htry = 0.01; /* * Now, bracket minimum. And do a bisection search for the minimum. */ done = FALSE; sgn = sgn0; P = Pa; Sb = -9e99; //printf("Htry =%g sgn = %g\n", Htry, sgn ); //printf("Xtarget = %g f = %g P = %g %g %g\n", Xtarget, f, P.x, P.y, P.z); while ( !done ) { //if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, 1.0e-7, sgn, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); if ( Lgm_MagStep( &P, &u_scale, Htry, &Hdid, &Hnext, sgn, &s, &reset, Info->Bfield, Info ) < 0 ) return(-1); Stotal += Hdid; ++Ntotal; R = Lgm_Magnitude( &P ); r2 = R*R; r3 = r2*R; L = r3 / (r2 - z2); f = Xtarget - P.x; //printf("Xtarget = %g f = %g P = %g %g %g\n", Xtarget, f, P.x, P.y, P.z); if ( (P.x > Info->OpenLimit_xMax) || (P.x < Info->OpenLimit_xMin) || (P.y > Info->OpenLimit_yMax) || (P.y < Info->OpenLimit_yMin) || (P.z > Info->OpenLimit_zMax) || (P.z < Info->OpenLimit_zMin) || ( s > 1000.0 ) ) { /* * Open FL! */ //v->x = v->y = v->z = 0.0; *v = P; //printf("OPEN!\n\n\n"); return(0); } else if ( r2 < 1.0 ) { return( -1 ); } else if ( (Stotal > 300.0) || ( Ntotal > 1500 ) ) { printf("Lgm_TraceToYZPlane: %s:%d Field line too long or too many iterations: Stotal / Ntotal: %g / %ld\n", __FILE__, __LINE__, Stotal, Ntotal ); return( 0 ); } else if ( fabs( f ) < tol ){ done = TRUE; } else if ( fsgn0*f > 0.0 ){ Pa = P; Sa += Hdid; sgn = sgn0; if ( bracketed ) { Htry = fabs( Sb - Sa )/2.0; } else if ( L < 4.5 ) { hhh = 1.165*L+1.0 - R + 1.0; //if ( hhh > 1e-4 ) Htry = hhh; if ( hhh > R-1.0 ) { hhh = (R-1.0)/2.0; } } /* printf("A: Sa, Sb, P = %g %g (%g, %g, %g) Htry = %f\n", Sa, Sb, P.x, P.y, P.z, Htry); */ } else { Pb = P; if ( bracketed ) Sb += sgn*sgn0*Hdid; else Sb = Sa + Hdid; bracketed = TRUE; sgn = -sgn0; Htry = fabs( Sb - Sa )/2.0; /* printf("B: Sa, Sb, P = %g %g (%g, %g, %g) Htry = %f\n", Sa, Sb, P.x, P.y, P.z, Htry); */ } } /* * */ *v = Pb; //printf("B: Sa, Sb, P = %g %g (%g, %g, %g) Htry = %f\n", Sa, Sb, P.x, P.y, P.z, Htry); // if ( fabs( Xtarget - Pb.x ) > 2.0*tol ) return( -1 ); return( 1 ); }
/* * Input Variables: * * Date: * UTC: * u: Input position vector in GSM * nAlpha: Number of Pitch Angles to compute * Alpha: Pitch Angles to compute * Quality: Quality factor (0-8) * * Input/OutPut Variables: * * MagEphemInfo: Structure used to input and output parameters/settings/results to/from routine. * */ void ComputeLstarVersusPA( long int Date, double UTC, Lgm_Vector *u, int nAlpha, double *Alpha, int Quality, Lgm_MagEphemInfo *MagEphemInfo ) { Lgm_LstarInfo *LstarInfo, *LstarInfo2, *LstarInfo3; Lgm_Vector v, v1, v2, v3, vv1, Bvec; double sa, sa2, Blocal; double Lam, CosLam, LSimple, dSa, dSb; int i, LS_Flag, nn, tk, ci; double Ival, Sbval, r, SS; int Kp=KP_DEFAULT; char Filename[128], *PreStr, *PostStr; FILE *fpout; LstarInfo = MagEphemInfo->LstarInfo; // Save Date, UTC to MagEphemInfo structure MagEphemInfo->Date = Date; MagEphemInfo->UTC = UTC; // Save nAlpha, and Alpha array to MagEphemInfo structure MagEphemInfo->nAlpha = nAlpha; for (i=0; i<MagEphemInfo->nAlpha; i++) MagEphemInfo->Alpha[i] = Alpha[i]; // Set Tolerances SetLstarTolerances( MagEphemInfo->LstarQuality, LstarInfo ); sprintf( Filename, "DipoleTest_1.05/results_%.0e.dat", LstarInfo->mInfo->Lgm_FindShellLine_I_Tol ); fpout = fopen(Filename, "w"); // set coord transformation Lgm_Set_Coord_Transforms( Date, UTC, LstarInfo->mInfo->c ); /* * Blocal at sat location. */ MagEphemInfo->P_gsm = *u; LstarInfo->mInfo->Bfield( u, &Bvec, LstarInfo->mInfo ); Blocal = Lgm_Magnitude( &Bvec ); MagEphemInfo->B = Blocal; /* * Compute Field-related quantities for each Pitch Angle. */ if ( Lgm_Trace( u, &v1, &v2, &v3, 120.0, 0.01, TRACE_TOL, LstarInfo->mInfo ) == 1 ) { MagEphemInfo->Pmin_gsm = v3; MagEphemInfo->Bmin = LstarInfo->mInfo->Bmin; /* * Get a simple measure of how big L is */ Lgm_Convert_Coords( &v1, &vv1, GSM_TO_SM, LstarInfo->mInfo->c ); Lam = asin( vv1.z/Lgm_Magnitude( &vv1 ) ); CosLam = cos( Lam ); LSimple = (1.0+120.0/WGS84_A)/( CosLam*CosLam ); { // ***** BEGIN PARALLEL EXECUTION ***** /* * Do all of the PAs in parallel. To control how many threads get run * use the enironment variable OMP_NUM_THREADS. For example, * setenv OMP_NUM_THREADS 8 * will use 8 threads to do the loop in parallel. Be very careful what gets * set private here -- the threads must not interfere with each other. */ #pragma omp parallel private(LstarInfo2,LstarInfo3,sa,sa2,dSa,dSb,LS_Flag,Ival,Sbval,nn,tk) #pragma omp for schedule(dynamic, 1) for ( i=0; i<MagEphemInfo->nAlpha; i++ ){ // LOOP OVER PITCH ANGLES // make a local copy of LstarInfo structure -- needed for multi-threading LstarInfo3 = Lgm_CopyLstarInfo( LstarInfo ); // colorize the diagnostic messages. sprintf( LstarInfo3->PreStr, "\033[38;5;%dm", Colors[i%9]); sprintf( LstarInfo3->PostStr, "\033[0m"); PreStr = LstarInfo3->PreStr; PostStr = LstarInfo3->PostStr; /* * Set Pitch Angle, sin, sin^2, and Bmirror */ sa = sin( MagEphemInfo->Alpha[i]*RadPerDeg ); sa2 = sa*sa; printf("%sComputing L* for Pitch Angle: Alpha[%d] = %g Date: %ld UTC: %g Lsimple = %g%s\n", PreStr, i, MagEphemInfo->Alpha[i], Date, UTC, LSimple, PostStr ); LstarInfo3->mInfo->Bm = Blocal/sa2; NewTimeLstarInfo( Date, UTC, MagEphemInfo->Alpha[i], LstarInfo3->mInfo->Bfield, LstarInfo3 ); MagEphemInfo->Bm[i] = LstarInfo3->mInfo->Bm; /* * Compute L* */ LstarInfo2 = Lgm_CopyLstarInfo( LstarInfo3 ); if ( LSimple < 10.0 ){ // USER SHOULD DECIDE THRESHOLD HERE LstarInfo2->mInfo->Bm = LstarInfo3->mInfo->Bm; if (LstarInfo3->VerbosityLevel >= 2 ) { printf("\n\n\t%sComputing L* for: UTC = %g PA = %d (%g)%s\n", PreStr, UTC, i, MagEphemInfo->Alpha[i], PostStr ); printf(" \t%s I = %g PA = %d (%g)%s\n", PreStr, MagEphemInfo->I[i], i, MagEphemInfo->Alpha[i], PostStr ); } LS_Flag = Lstar( &v3, LstarInfo2); if (LstarInfo3->VerbosityLevel >= 2 ) { printf("\t%sUTC, L* = %g %g%s\n", PreStr, UTC, LstarInfo2->LS, PostStr ); printf("\t%sUTC, L*_McIlwain = %g %g%s\n", PreStr, UTC, LstarInfo2->LS_McIlwain_M, PostStr ); printf("\t%sUTC, LSimple = %g %g%s\n\n\n", PreStr, UTC, LSimple, PostStr ); } MagEphemInfo->Lstar[i] = LstarInfo2->LS; /* * Save results to the MagEphemInfo structure. */ MagEphemInfo->nShellPoints[i] = LstarInfo2->nPnts; for (nn=0; nn<LstarInfo2->nPnts; nn++ ){ MagEphemInfo->ShellI[i][nn] = LstarInfo2->I[nn]; MagEphemInfo->ShellFootprint_Pn[i][nn] = LstarInfo2->Footprint_Pn[nn]; MagEphemInfo->ShellFootprint_Ps[i][nn] = LstarInfo2->Footprint_Ps[nn]; MagEphemInfo->ShellMirror_Pn[i][nn] = LstarInfo2->Mirror_Pn[nn]; MagEphemInfo->ShellMirror_Ps[i][nn] = LstarInfo2->Mirror_Ps[nn]; MagEphemInfo->ShellMirror_Ss[i][nn] = LstarInfo2->mInfo->Sm_South; MagEphemInfo->ShellMirror_Sn[i][nn] = LstarInfo2->mInfo->Sm_North; /* * Save all of the drift shell FLs in MagEphemInfo structure */ MagEphemInfo->nFieldPnts[i][nn] = LstarInfo2->nFieldPnts[nn]; for (tk=0; tk<LstarInfo2->nFieldPnts[nn]; tk++){ // loop over points in a FL MagEphemInfo->s_gsm[i][nn][tk] = LstarInfo2->s_gsm[nn][tk]; MagEphemInfo->Bmag[i][nn][tk] = LstarInfo2->Bmag[nn][tk]; MagEphemInfo->x_gsm[i][nn][tk] = LstarInfo2->x_gsm[nn][tk]; MagEphemInfo->y_gsm[i][nn][tk] = LstarInfo2->y_gsm[nn][tk]; MagEphemInfo->z_gsm[i][nn][tk] = LstarInfo2->z_gsm[nn][tk]; } } } else { printf(" Lsimple >= 10.0 ( Not doing L* calculation )\n" ); } fprintf(fpout, "%.15lf %.15lf\n", MagEphemInfo->Alpha[i], (1.05-LstarInfo2->LS)/LstarInfo->mInfo->Lgm_FindShellLine_I_Tol ); fflush(fpout); FreeLstarInfo( LstarInfo2 ); FreeLstarInfo( LstarInfo3 ); } } // ***** END PARALLEL EXECUTION ***** } // FreeLstarInfo( LstarInfo ); fclose(fpout); return; }
int main(){ long int Date; double UTC; Lgm_Vector u, B, CurlB; Lgm_MagModelInfo *mInfo; int i, j; Date = 20050831; UTC = 9.0; mInfo = Lgm_InitMagInfo( ); Lgm_Set_Coord_Transforms( Date, UTC, mInfo->c ); mInfo->Bfield = Lgm_B_TS04; //mInfo->Bfield = Lgm_B_OP77; //mInfo->Bfield = Lgm_B_T89; mInfo->Bfield = Lgm_B_TS04; mInfo->Bfield = Lgm_B_igrf; mInfo->Bfield = Lgm_B_cdip; mInfo->Bfield = Lgm_B_edip; mInfo->Bfield = Lgm_B_T89; mInfo->P = 4.1011111111111118; mInfo->Dst = 7.7777777777777777; mInfo->By = 3.7244444444444444; mInfo->Bz = -0.12666666666666665; mInfo->W[0] = 0.12244444444444445; mInfo->W[1] = 0.2514; mInfo->W[2] = 0.089266666666666661; mInfo->W[3] = 0.047866666666666668; mInfo->W[4] = 0.22586666666666666; mInfo->W[5] = 1.0461333333333334; printf("%13s", "Kp"); printf(" %13s", "Ux (Re)"); printf(" %13s", "Uy (Re)"); printf(" %13s", "Uz (Re)"); printf(" %13s", "Bx (nT)"); printf(" %13s", "By (nT)"); printf(" %13s", "Bz (nT)"); printf(" %13s", "Bmag (nT)"); printf(" %16s", "CurlB_x (nT/Re)"); printf(" %16s", "CurlB_y (nT/Re)"); printf(" %16s", "CurlB_z (nT/Re)\n"); for (i=0; i<=5; i++) { mInfo->Kp = i; u.x = -6.6; u.y = 0.0; u.z = 0.0; mInfo->Bfield( &u, &B, mInfo ); Lgm_CurlB( &u, &CurlB, LGM_DERIV_SIX_POINT, 1e-3, mInfo ); printf( "%13i", mInfo->Kp); printf( " %13g %13g %13g", u.x, u.y, u.z ); printf( " %13g %13g %13g", B.x, B.y, B.z ); printf( " %13g", Lgm_Magnitude( &B ) ); printf( " %16g %16g %16g \n", CurlB.x, CurlB.y, CurlB.z ); } for (j=0; j<100; j++){ mInfo->Kp = 3; for (i=0; i<13; i++) { u.x = -1. - (double)i * 0.5; u.y = 1.0; u.z = -1.0; mInfo->Bfield( &u, &B, mInfo ); Lgm_CurlB( &u, &CurlB, LGM_DERIV_SIX_POINT, 1e-3, mInfo ); printf( "%13i", mInfo->Kp); printf( " %13g %13g %13g", u.x, u.y, u.z ); printf( " %13g %13g %13g", B.x, B.y, B.z ); printf( " %13g", Lgm_Magnitude( &B ) ); printf( " %16g %16g %16g \n", CurlB.x, CurlB.y, CurlB.z ); } } { Lgm_Vector v; mInfo->Lgm_VelStep_T = 100e-3; // 100keV mInfo->Lgm_VelStep_q = -LGM_e; // electron change mInfo->Lgm_VelStep_E0 = LGM_Ee0; // electron mass mInfo->Lgm_VelStep_Bm = sqrt(B.x*B.x + B.y*B.y + B.z*B.z); // b mirror [nT] mInfo->Lgm_VelStep_h = 1e-3; // step size in Re mInfo->Lgm_VelStep_DerivScheme = LGM_DERIV_FOUR_POINT; printf("\nT=%lf q=%lf E0=%lf Bm=%lf h=%lf DerivScheme=%d\n", mInfo->Lgm_VelStep_T, mInfo->Lgm_VelStep_q, mInfo->Lgm_VelStep_E0, mInfo->Lgm_VelStep_Bm, mInfo->Lgm_VelStep_h, mInfo->Lgm_VelStep_DerivScheme ); Lgm_GradAndCurvDriftVel(&u, &v, mInfo); printf("\nThe drift velocity [km/s in GSM] for a locally mirroring 100 keV electron is:\n"); Lgm_PrintVector(&v); } Lgm_FreeMagInfo( mInfo ); exit(0); }