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 );

}
Example #2
0
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 );
    
}
Example #3
0
/**
 *  \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

}
Example #4
0
/*
 * 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);
    }
}
Example #5
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);

}
Example #6
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;
}
Example #7
0
/* 
 *  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 ) );
}
Example #8
0
/**
 *  \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 );

}
Example #11
0
/**
 *  \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 );
    

}
Example #15
0
/*
 *      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);
    }
Example #16
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;

}
Example #18
0
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);
}