int main(){ long int Date; double L, I, Bm, M, a, UTC, Ltarget; Lgm_Vector u, v; Lgm_MagModelInfo *mInfo = Lgm_InitMagInfo(); Lgm_CTrans *c = Lgm_init_ctrans( 0 ); Lgm_ElapsedTimeInfo tInfo; Lgm_ElapsedTimeInit( &tInfo, 255, 95, 0 ); for (Ltarget=1.5; Ltarget<16.0; Ltarget += 0.1){ //Ltarget = 5.0; Date = 20100101; UTC = 0.0; Lgm_Set_Coord_Transforms( Date, UTC, c ); u.x = -Ltarget; u.y = 0.0; u.z = 0.0; // SM Lgm_Convert_Coords( &u, &v, SM_TO_GSM, c ); mInfo->Bfield = Lgm_B_cdip; for (a=5.0; a<=90.0; a+= 5.0){ L = Lgm_McIlwain_L( Date, UTC, &v, a, 0, &I, &Bm, &M, mInfo ); printf("Pitch Angle: %g McIlwain L = %.10g ( I, Bm, M = %g %g %g ) Delta = %g\n", a, L, I, Bm, M, Ltarget-L); } } Lgm_PrintElapsedTime( &tInfo ); Lgm_FreeMagInfo(mInfo); Lgm_free_ctrans(c); return(0); }
/** * 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; }
/* * 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); }
/* * 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 ); }
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 ); }
int Lgm_TraceToSMEquat( Lgm_Vector *u, Lgm_Vector *v, double tol, Lgm_MagModelInfo *Info ) { Lgm_Vector u_scale; double Htry, Hdid, Hnext, Hmin, Hmax, s, sgn, r2; double Sa=0.0, Sb=0.0, Sc=0.0, d1, d2; double Za, Zb, Zc, Z; Lgm_Vector Ztmp; Lgm_Vector Pa, Pb, Pc, P; int done, reset; Hmax = 20.0; Hmin = 0.001; u_scale.x = 100.0; u_scale.y = 100.0; u_scale.z = 100.0; Za = Zb = Zc = 0.0; /* * Bracket the minimum. We want to find two points along * the field line such that the location of equatorial plane is * gauranteed to lie between them. To do this, we need to find * three points; Pa, Pb, and Pc such that; * * Pc > Pb > Pa * * and |z_sm( Pa )| > |z_sm( Pb )| * and |z_sm( Pc )| > |z_sm( Pb )| * * */ /* * Set the start point, Pa and Za (the absolute value of the SM z coord). */ Pa = *u; Lgm_Convert_Coords( &Pa, &Ztmp, GSM_TO_SM, Info->c ); Za = fabs( Ztmp.z ); Sa = 0.0; /* * If we are above the SM plane (i.e. in the northern hemisphere), lets * try tracing against the field direction. */ sgn = ( Ztmp.z > 0.0 ) ? -1.0 : 1.0; /* * Keep stepping along the field line until we have a |Zsm| less than the start point. */ P = Pa; done = FALSE; Htry = Za; 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); Lgm_Convert_Coords( &P, &Ztmp, GSM_TO_SM, Info->c ); Z = fabs( Ztmp.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) ) { /* * Open FL! */ v->x = v->y = v->z = 0.0; return(0); } else if ( Z < Za ) { done = TRUE; Pb = P; Zb = Z; Sb += Hdid; } else { Pa = P; Za = Z; Sa = 0.0; } Htry = Z; } /* * Keep stepping along the field line until we complete the bracket triple. */ done = FALSE; while (!done) { P = Pb; //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); Lgm_Convert_Coords( &P, &Ztmp, GSM_TO_SM, Info->c ); Z = fabs( Ztmp.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) ) { /* * Open FL! */ v->x = v->y = v->z = 0.0; return(0); } else if ( Z < Zb ) { Pa = Pb; Za = Zb; Sa = 0.0; Pb = P; Zb = Z; Sb = Hdid; r2 = P.x*P.x + P.y*P.y + P.z*P.z; Htry = (Hnext < Hmax) ? ((Hnext > Hmin) ? Hnext : Hmin) : Hmax; if (Htry*Htry > r2) Htry = 0.25*sqrt(r2); } else { Pc = P; Zc = Z; Sc = Sb + Hdid; done = TRUE; } } /* * We have a bracket. Now go in for the kill. * 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). */ done = FALSE; while (!done) { d1 = Sb; d2 = Sc - Sb; if ( Sc < tol ) { done = TRUE; } else if ( d1 > d2 ) { P = Pa; Htry = 0.381966011*d1; //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); Lgm_Convert_Coords( &P, &Ztmp, GSM_TO_SM, Info->c ); Z = fabs( Ztmp.z ); if ( Z < Zb ) { Pb = P; Zb = Z; Sb = Hdid; } else { Pa = P; Za = Z; Sb -= Hdid; Sc -= Hdid; } } else { P = Pb; Htry = 0.381966011*d2; //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); Lgm_Convert_Coords( &P, &Ztmp, GSM_TO_SM, Info->c ); Z = fabs( Ztmp.z ); if ( Z < Zb ) { Pb = P; Zb = Z; Sb += Hdid; } else { Pc = P; Zc = Z; Sc = Sb + Hdid; } } } *v = Pb; return( 1 ); }
int main( int argc, char *argv[] ){ double UTC, Alpha[1000], a; long int Date; int nAlpha, Kp, i; Lgm_Vector P, Pgsm; Lgm_CTrans *c = Lgm_init_ctrans(0); Lgm_MagModelInfo *mmi = Lgm_InitMagInfo(); Lgm_MagEphemInfo *MagEphemInfo = Lgm_InitMagEphemInfo(0, 20); FILE *fp; mmi->Lgm_MagStep_Integrator = LGM_MAGSTEP_ODE_BS; // Date and UTC Date = 20130327; Date = 20000701; Date = 20130101; Date = 20130322; UTC = 4.0 + 0.0/60.0 + 0.0/3600.0; UTC = 0.0 + 0.0/60.0 + 0.0/3600.0; Lgm_Set_Coord_Transforms( Date, UTC, c ); MagEphemInfo->LstarInfo->LSimpleMax = 35.0; MagEphemInfo->LstarInfo->mInfo->Lgm_MagStep_Integrator = LGM_MAGSTEP_ODE_BS; MagEphemInfo->LstarInfo->nFLsInDriftShell = 96; MagEphemInfo->nFLsInDriftShell = 96; //USER INPUT STUFF MagEphemInfo->LstarQuality = 3; Lgm_SetLstarTolerances( 3, 96, MagEphemInfo->LstarInfo ); MagEphemInfo->SaveShellLines = TRUE; MagEphemInfo->LstarInfo->VerbosityLevel = 1; MagEphemInfo->LstarInfo->ISearchMethod = 2; MagEphemInfo->LstarInfo->mInfo->VerbosityLevel = 0; Kp = 2; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_cdip; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_T89; MagEphemInfo->LstarInfo->mInfo->Kp = ( Kp >= 0 ) ? Kp : KP_DEFAULT; if ( MagEphemInfo->LstarInfo->mInfo->Kp > 5 ) MagEphemInfo->LstarInfo->mInfo->Kp = 5; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_cdip; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_OP77; MagEphemInfo->LstarInfo->mInfo->InternalModel = LGM_IGRF; MagEphemInfo->LstarInfo->mInfo->InternalModel = LGM_CDIP; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_Dungey; MagEphemInfo->LstarInfo->mInfo->Bfield = Lgm_B_T89c; MagEphemInfo->LstarInfo->mInfo->c->psi = 0.0; FILE *fpjunk; int done; char fname[1024]; double Ra, Rc, Fa, Fc, R, F, Phi, Lat, MLT, Fmax, Rmax; double Kin = 1.5; sprintf(fname, "junk_K_v5_24.txt" ); fpjunk = fopen(fname, "w"); for (MLT=1.5; MLT<=1.5; MLT+=0.05){ done = FALSE; Ra = 5.0; Phi = (MLT*15.0 - 180.0)*RadPerDeg; Lat = 0.0*RadPerDeg; P.x = Ra*cos( Phi )*cos(Lat); P.y = Ra*sin( Phi )*cos(Lat); P.z = Ra*sin(Lat); Lgm_Convert_Coords( &P, &Pgsm, SM_TO_GSM, c ); Fa = LS( Date, UTC, Kin, &Pgsm, MagEphemInfo ); // WriteMagEphemInfoStruct( "test.dat", 1, MagEphemInfo ); //exit(0); Rc = 30.0; Phi = (MLT*15.0 - 180.0)*RadPerDeg; Lat = 0.0*RadPerDeg; P.x = Rc*cos( Phi )*cos(Lat); P.y = Rc*sin( Phi )*cos(Lat); P.z = Rc*sin(Lat); Lgm_Convert_Coords( &P, &Pgsm, SM_TO_GSM, c ); Fc = LS( Date, UTC, Kin, &Pgsm, MagEphemInfo ); Fmax = -1.0; if ( (Fc < 0.0) && (Fa>0.0) ) { while (!done ) { R = (Ra+Rc)/2.0; printf("R = %g\n", R); Phi = (MLT*15.0 - 180.0)*RadPerDeg; Lat = 0.0*RadPerDeg; P.x = R*cos( Phi )*cos(Lat); P.y = R*sin( Phi )*cos(Lat); P.z = R*sin(Lat); Lgm_Convert_Coords( &P, &Pgsm, SM_TO_GSM, c ); F = LS( Date, UTC, Kin, &Pgsm, MagEphemInfo ); if ( F < 0.0 ) { Rc = R; Fc = F; } else { if ( F > Fmax ) { Fmax = F; Rmax = R; }; Ra = R; Fa = F; } if ( fabs(Rc-Ra) < 1e-3 ) done = TRUE; } } else { printf("No bracket!\n"); } if (Fmax > Fa) printf("************************* Fmax, Fa = %g %g\n", Fmax, Fa); fprintf( fpjunk, "%g %g\n", MLT, Fa ); fflush(fpjunk); } fclose(fpjunk); MLT = 3.00; Phi = (MLT*15.0 - 180.0)*RadPerDeg; Lat = 0.0*RadPerDeg; P.x = Ra*cos( Phi )*cos(Lat); P.y = Ra*sin( Phi )*cos(Lat); P.z = Ra*sin(Lat); Lgm_Convert_Coords( &P, &Pgsm, SM_TO_GSM, c ); F = LS( Date, UTC, Kin, &Pgsm, MagEphemInfo ); WriteMagEphemInfoStruct( "test.dat", 1, MagEphemInfo ); fp = fopen("Lstar.dat", "w"); for ( i=0; i<nAlpha; ++i ) { fprintf( fp, "%g %.10lf\n", Alpha[i], MagEphemInfo->Lstar[i] ); } fclose(fp); Lgm_free_ctrans( c ); Lgm_FreeMagEphemInfo( MagEphemInfo ); return(0); }
void ComputeZPSTransMatrix( Lgm_Vector *Rgeo, long int Date, double UT, double Agsm_to_ins[3][3], double Ains_to_gsm[3][3], double Qins_to_gsm[4], double Qgsm_to_ins[4] ) { double Glon, Alpha, A, B, ca, sa, sum; Lgm_Vector Xgeo, Ygeo, Zgeo, Xgsm, Ygsm, Zgsm; Lgm_Vector Ngeo, Egeo, Ngsm, Egsm; Lgm_Vector Xsc_geo,Ysc_geo, Zsc_geo; Lgm_Vector Xsc_gsm,Ysc_gsm, Zsc_gsm; double Agsm_to_sc[3][3], Asc_to_gsm[3][3], Asc_to_r3[3][3], Ar3_to_sc[3][3], Asc_to_dom[3][3], Adom_to_sc[3][3]; Lgm_Vector X1, Y1, Z1; Lgm_Vector X2, Y2, Z2; Lgm_Vector X3, Y3, Z3; Lgm_Vector X4, Y4, Z4; int i, j, k; Lgm_CTrans c; Lgm_Vector Xins, Yins, Zins, Xsc, Ysc, Zsc; Lgm_Vector Xins_new, Yins_new, Zins_new; double Q1[4], Q2[4], Q3[4], QQ[4], QT1[4]; Glon = atan2( Rgeo->y, Rgeo->x ); /* * Compute transformation matrix from dome coords to GSM * Assume spacecraft is located at Rgeo. */ /* * Nadir in GEO coords. */ Ngeo.x = -Rgeo->x; Ngeo.y = -Rgeo->y; Ngeo.z = -Rgeo->z; Lgm_NormalizeVector( &Ngeo ); /* * East in GEO coords. Since, r = {cos(phi), sin(phi)} * east direction will be dr/dphi which is; * * east = {-sin(phi), cos(phi)} * * note that phi is just glon in GEO coords. * */ Egeo.x = -1.0*sin(Glon); Egeo.y = cos(Glon); Egeo.z = 0.0; /* * North in GEO coords. */ Zgeo.x = 0.0; Zgeo.y = 0.0; Zgeo.z = 1.0; /* * Define S/C coords as: * X: East * Y: South * Z: Nadir */ Xsc_geo = Egeo; Ysc_geo.x = -Zgeo.x; Ysc_geo.y = -Zgeo.y; Ysc_geo.z = -Zgeo.z; Zsc_geo = Ngeo; /* * Convert to GSM */ Lgm_Set_Coord_Transforms( Date, UT, &c ); Lgm_Convert_Coords( &Xsc_geo, &Xsc_gsm, GEO_TO_GSM, &c ); Lgm_Convert_Coords( &Ysc_geo, &Ysc_gsm, GEO_TO_GSM, &c ); Lgm_Convert_Coords( &Zsc_geo, &Zsc_gsm, GEO_TO_GSM, &c ); Xsc_gsm = Xsc_geo; Ysc_gsm = Ysc_geo; Zsc_gsm = Zsc_geo; /* * Construct Transformation Matrix from GSM to S/C */ Agsm_to_sc[0][0] = Xsc_gsm.x, Agsm_to_sc[1][0] = Xsc_gsm.y, Agsm_to_sc[2][0] = Xsc_gsm.z; Agsm_to_sc[0][1] = Ysc_gsm.x, Agsm_to_sc[1][1] = Ysc_gsm.y, Agsm_to_sc[2][1] = Ysc_gsm.z; Agsm_to_sc[0][2] = Zsc_gsm.x, Agsm_to_sc[1][2] = Zsc_gsm.y, Agsm_to_sc[2][2] = Zsc_gsm.z; Asc_to_gsm[0][0] = Xsc_gsm.x, Asc_to_gsm[1][0] = Ysc_gsm.x, Asc_to_gsm[2][0] = Zsc_gsm.x; Asc_to_gsm[0][1] = Xsc_gsm.y, Asc_to_gsm[1][1] = Ysc_gsm.y, Asc_to_gsm[2][1] = Zsc_gsm.y; Asc_to_gsm[0][2] = Xsc_gsm.z, Asc_to_gsm[1][2] = Ysc_gsm.z, Asc_to_gsm[2][2] = Zsc_gsm.z; printf(" ( %5g %5g %5g )\n", Asc_to_gsm[0][0], Asc_to_gsm[1][0], Asc_to_gsm[2][0] ); printf("Asc_to_gsm = ( %5g %5g %5g )\n", Asc_to_gsm[0][1], Asc_to_gsm[1][1], Asc_to_gsm[2][1] ); printf(" ( %5g %5g %5g )\n", Asc_to_gsm[0][2], Asc_to_gsm[1][2], Asc_to_gsm[2][2] ); /* * Now construct trans matrix between S/C and INSTRUMENT * * Lets define the instrument coord system to be as follows: * Yins: parallel to instrument cylindrical symmetry axis. * Zins: parallel to FOV of */ /* * Here is the prescription to orient ZPS: * * 1. Start with Yins parallel to Ysc and Zins parallel to Zsc * 2. Rotate by -29 deg. about Zsc * 3. Then rotate by +45.5 deg. about Yins * 4. Then roate by +30.0 deg. about Zins * * The easiest way to do this is to use Quaternions * */ // Step 1 Xins = Xsc_gsm; Yins = Ysc_gsm; Zins = Zsc_gsm; // Step2 //Lgm_AxisAngleToQuat( &Zins, -29.0, Q1 ); Lgm_AxisAngleToQuat( &Zins, 0.0, Q1 ); Lgm_QuatRotateVector( Q1, &Xins, &Xins_new ); Xins = Xins_new; Lgm_QuatRotateVector( Q1, &Yins, &Yins_new ); Yins = Yins_new; Lgm_QuatRotateVector( Q1, &Zins, &Zins_new ); Zins = Zins_new; // Step3 //Lgm_AxisAngleToQuat( &Yins, 45.5, Q2 ); Lgm_AxisAngleToQuat( &Yins, 0.0, Q2 ); Lgm_QuatRotateVector( Q2, &Xins, &Xins_new ); Xins = Xins_new; Lgm_QuatRotateVector( Q2, &Yins, &Yins_new ); Yins = Yins_new; Lgm_QuatRotateVector( Q2, &Zins, &Zins_new ); Zins = Zins_new; // Step4 //Lgm_AxisAngleToQuat( &Zins, 30.0, Q3 ); Lgm_AxisAngleToQuat( &Zins, 0.0, Q3 ); Lgm_QuatRotateVector( Q3, &Xins, &Xins_new ); Xins = Xins_new; Lgm_QuatRotateVector( Q3, &Yins, &Yins_new ); Yins = Yins_new; Lgm_QuatRotateVector( Q3, &Zins, &Zins_new ); Zins = Zins_new; /* * Now, Xins, Yins, Zins will be oriented in their final positions. * We can construct the sc -> ins trans matrix in one of two wyas now. * 1. combine all of the quats and then convert Q->matrix * or 2. use the final unit vectors to manually construct the matri. * Try both... */ Lgm_QuatCombineQuats( Q1, Q2, QT1 ); Lgm_QuatCombineQuats( QT1, Q3, QQ ); for (i=0; i<4; i++) Qins_to_gsm[i] = QQ[i]; Lgm_Quat_To_Matrix( QQ, Ains_to_gsm ); for (i=0; i<3; ++i){ for (j=0; j<3; ++j){ Agsm_to_ins[i][j] = Ains_to_gsm[j][i]; } } Lgm_MatrixToQuat( Agsm_to_ins, Qgsm_to_ins ); Lgm_MatrixToQuat( Agsm_to_sc, Qgsm_to_ins ); Lgm_MatrixToQuat( Asc_to_gsm, Qins_to_gsm ); }
/* * 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; }