示例#1
0
 def trace_drift_shell(self,sm_loc,t_loc,Ech,sinA_loc,sim_dt,verbose=True,Vdip_inj=None):
     # This function is an improve version of trace_drift, it accept coordinates in SM as a vector
     # And the time as datetime parameter
     # Input parameters
     # 1- Date and time of the injection
     #-------------------------------------------------------------------------------#
     #_date = self.date
     _imod = self.imod        # magnetic field model: 0=dipole, 1=T96_01, 2=T01_1, 3=T04_s
     _ipot = self.ipot        # electric field model: 1=Weimer, 2=CIMI 
     _itrace = self.itrace      # 1=forward, -1=backward tracing
     #_tsec0 = self.tsec       # initial time in second
     #_tend = self.tend     # end time in second
     #_ro = self.ro          # initial radial distance in RE
     #_mlt = self.mlt         # initial mlt in hour
     _ekev0 = Ech      # initial energy in keV
     _ion= self.ion          # 1=ion, -1=electron
     _tf = self.tf         # time resolution in seconds in updating omni parameters
     #-------------------------------------------------------------------------------#
     ### Main trace_drift subroutine 
     pi=np.pi
     dra=_itrace*0.5*pi/180.           # drift path tracing step size in radian
     iprint=1                         # print result every iprint steps
     re=6.371e6                       # Earth's radius (m)
     if (_ion == 1): Eo=9.38269e5      # proton rest energy
     if (_ion == -1): Eo=511.          # electron rest energy
     Eo2=Eo*Eo
     pc_sq=(_ekev0+Eo)**2-Eo2         # (pc)^2 in keV^2
     latmax=72.*pi/180.              # max allowable latitude at the ionosphere
     reqmax=10.                      # max allowable equatorial distance
     istepmax=3000                   # max allowable istep
     rc=1.
     #Find dipole moment
     iyear = t_loc.year
     dts = spt.Ticktock(t_loc)
     iday = dts.DOY
     tsec0_dt = t_loc
     parmod,nsw,vxgse,vygse,vzgse = self.TsyParmod(tsec0_dt,_imod)# vy and vz are 0 to ensure GSM coordinate system
     tsygFort.recalc_08(iyear,iday,tsec0_dt.hour,tsec0_dt.minute,tsec0_dt.second,vxgse,vygse,vzgse)
     GGG=tsygFort.geopack2.g
     HHH=tsygFort.geopack2.h
     DIPMOM=np.sqrt(GGG[1]**2+GGG[2]**2+HHH[2]**2)   # DIPMOM in (nT RE^3)
     xme=DIPMOM*re**3*1.e-9                       # dipole moment in (T m^3)
     #xme = np.exp(36.58626097)
     
     # Find the initial ionospheric projection (along field line) point
     #phi=_mlt*pi/12.               
     #xeq=-_ro*np.cos(phi)              # +x --> Sun
     #yeq=-_ro*np.sin(phi)
     #zeq=0.
     lati,mlti = self.mapping(_imod,parmod,sm_loc[0],sm_loc[1],sm_loc[2],0,0,1)
     x0 = np.zeros(2)
     x0[0]=lati                 # latitude in radian
     x0[1]=mlti                 # local time in radian
     xeq,yeq,zeq,iout=self.mapping(_imod,parmod,0,0,0,x0[0],x0[1],-1)
     # find Bmag, sinA at the initial position and the invariant pcy2B
     bx,by,bz,Bmag=self.Tsy_w_dip(_imod,parmod,xeq,yeq,zeq) # find B at magnetic equator
     bx,by,bz,Bloc=self.Tsy_w_dip(_imod,parmod,sm_loc[0],sm_loc[1],sm_loc[2]) # find B at local position
     _sinA=np.sqrt(Bmag/Bloc*sinA_loc*sinA_loc) # Pitch angle at the magnetic equator
     if _sinA > 1:
         _sinA = 1
         print('Warning: B at the equator > B loc, possible orbit bifurcation. Temp solution make sin(PA)=1')
         #ipdb.set_trace()
     if (np.arcsin(_sinA) >= 80/180*pi): # if PA > 80 we consider as 90 degrees.
         print('Warning: real PA is %4.2f, as it is > 80 we assume 90' %(np.arcsin(_sinA)*180/pi) )
         _sinA = 1
         self.pcy2B=pc_sq*_sinA*_sinA/Bmag  # First invariant, Bmag = B at equator
         self.K = 0.
     else:
         self.pcy2B=pc_sq*_sinA*_sinA/Bmag  # First invariant, Bmag = B at equator
         self.K = self.KofAlpha(np.arcsin(_sinA),lati,mlti,_imod,parmod) # Second invariant K
     # Print the initial condition
     #ipdb.set_trace()
     pitchA=np.arcsin(_sinA)*180./pi
     Lshell=rc/(np.cos(lati))**2
     mlti_d=mlti*12./pi              # mlt at ionosphere in hour
     ro_loc=np.sqrt(sm_loc[0]*sm_loc[0]+sm_loc[1]*sm_loc[1]+sm_loc[2]*sm_loc[2])
     phi=np.arctan2(sm_loc[1],sm_loc[0])
     mlt_loc=phi*12./pi+12.
     print('Info: the first line show Ro local and mlt local, i.e at the pos of the S/C and not at the equator')
     print('%i %i %i %i %i %4.2f ! iyear,iday,imod,ipot,ion,tf' %(iyear,iday,_imod,_ipot,_ion,_tf))
     print('  tsec             Dst    Lshell    mlti       ro     mlto     ekeV    PA   Vsw   Pdyn')
     print('%s %7.0f %9.3f %9.3f  %9.3f %6.3f  %6.1f %6.2f' %(tsec0_dt.isoformat()\
                                                              ,parmod[1],Lshell,mlti_d,ro_loc,mlt_loc,_ekev0,pitchA))
     #ipdb.set_trace()
     # Start drift path tracing
     epoch = dt.datetime(1970,1,1)
     _tend=(tsec0_dt-epoch).total_seconds() + _itrace*sim_dt # UTC seconds since epoch time
     tsec=(tsec0_dt-epoch).total_seconds() # UTC seconds since epoch time
     istep=0
     iexit=0
     lastprint=0
     iexit=0
     vswi=vxgse
     xnswi = nsw
     Dst0 = parmod[1]
     xeq0=0;yeq0=0;zeq0=0
     ##
     roarr=np.zeros(istepmax)
     mltoarr=np.zeros(istepmax)
     #tsecarr=np.zeros(istepmax)
     tsecarr = []
     Eoarr = np.zeros(istepmax)
     pitchAarr = np.zeros(istepmax)
     if Vdip_inj!=None:
         #ipdb.set_trace()
         vdip = self.Vdip_i(Vdip_inj,_imod,parmod) ## Added May 25, simulate injection
     else:
         vdip = 0
     ## Start debugging 
     while (iexit != 1):
         #ipdb.set_trace() 
         xend,dtsec=self.rk4(_imod,_ipot,parmod,vswi,xnswi,_ion,dra,Eo,xme,x0,_sinA,veldip=vdip)
         if (np.arcsin(_sinA) < 80/180*pi):
             _Alpha,_Bmag = self.AlphaOfK(self.K,xend[0],xend[1],_imod,parmod)
             _sinA = np.sin(_Alpha)
         else: _sinA = 1
         # update istep, tsec, Bmag
         istep=istep+1
         tsec=tsec+dtsec
         xeq,yeq,zeq,iout=self.mapping(_imod,parmod,0,0,0,xend[0],xend[1],-1)
         req=np.sqrt(xeq*xeq+yeq*yeq)
         # test for exit or continue
         if (istep==istepmax): iexit=1
         if (iout==1): iexit=1            
         if (xend[0]>=latmax): 
             iexit=1
             print('Warning: xend[0]>=latmax')
         if (req>=reqmax): iexit=1
         if ((_itrace==1) and (tsec>=_tend)): iexit=1            
         if ((_itrace==-1) and (tsec<=_tend)): iexit=1
         # Reasign values if iexit.eq.1
         if (iexit==1):
             #ipdb.set_trace()
             tsec=tsec-dtsec
             xend=x0
             parmod[1]=Dst0
             xeq=xeq0
             yeq=yeq0
             zeq=zeq0
             req=np.sqrt(xeq*xeq+yeq*yeq)
             if (tsec>=tprint): lastprint=1
         # print result every iprint step and at the end of the trace
         if ((np.mod(istep,iprint)==0) or (lastprint==1)):
             bx,by,bz,Bmag = self.Tsy_w_dip(_imod,parmod,xeq,yeq,zeq)
             #ipdb.set_trace()
             pc_sq=self.pcy2B*Bmag/_sinA/_sinA
             ekev=np.sqrt(pc_sq+Eo2)-Eo
             pitchA=np.arcsin(_sinA)*180./pi
             Lshell=rc/(np.cos(xend[0]))**2
             mlti_d=xend[1]*12./pi ## mlt at ionosphere in hour
             phi=np.arctan2(yeq,xeq)
             mlteq=phi*12./pi+12.
             tprint=tsec
             roarr[istep-1]=req ## variables for ploting
             mltoarr[istep-1]=mlteq
             #tsecarr[istep-1]= tsec
             tsecarr.append(epoch + timedelta(seconds=tsec))
             Eoarr[istep-1]=ekev
             pitchAarr[istep-1] = pitchA
             if verbose == True:
                 print('%s %7.0f %9.3f %9.3f  %9.3f %6.3f  %6.1f %6.2f %7.2f %6.4f'\
                       %(tsecarr[istep-1].isoformat(),parmod[1],Lshell,mlti_d,req,mlteq,ekev,pitchA,vswi,parmod[0]))
         # Save values 
         Dst0=parmod[1]
         xeq0=xeq
         yeq0=yeq
         zeq0=zeq
         # Update x0 and Tsyganenko parmod
         x0=xend
         if istep==1: dstep = int(_tf/dtsec) # choose an aproximate dt step for changing SW parameters
         if np.mod(istep,dstep)==0: 
             parmod,xnswi,vswi,vygse,vzgse = self.TsyParmod(tsecarr[istep-1],_imod)
     return tsecarr,mltoarr,roarr,Eoarr,pitchAarr,istep
示例#2
0
    def trace(self,
              lat=None,
              lon=None,
              rho=None,
              coords=None,
              datetime=None,
              vswgse=None,
              pdyn=None,
              dst=None,
              byimf=None,
              bzimf=None,
              lmax=5000,
              rmax=60.,
              rmin=1.,
              dsmax=0.01,
              err=0.000001):
        """See tsygTrace for a description of each parameter
        Any unspecified parameter default to the one stored in the object
        Unspecified lmax, rmax, rmin, dsmax, err has a set default value

        Parameters
        ----------
        lat : Optional[ ]
            latitude [degrees]
        lon : Optional[ ]
            longitude [degrees]
        rho : Optional[ ]
            distance from center of the Earth [km]
        coords : Optional[str]
            coordinates used for start point ['geo']
        datetime : Optional[datetime]
            a python datetime object
        vswgse : Optional[list, float]
            solar wind velocity in GSE coordinates [m/s, m/s, m/s]
        pdyn : Optional[float]
            solar wind dynamic pressure [nPa]
        dst : Optional[flaot]
            Dst index [nT]
        byimf : Optional[float]
            IMF By [nT]
        bzimf : Optional[float]
            IMF Bz [nT]
        lmax : Optional[int]
            maximum number of points to trace
        rmax : Optional[float]
            upper trace boundary in Re
        rmin : Optional[float]
            lower trace boundary in Re
        dsmax : Optional[float]
            maximum tracing step size
        err : Optional[float]
            tracing step tolerance

        Written by Sebastien 2012-10

        """

        from numpy import radians, degrees, zeros

        # Store existing values of class attributes in case something is wrong
        # and we need to revert back to them
        if lat: _lat = self.lat
        if lon: _lon = self.lon
        if rho: _rho = self.rho
        if coords: _coords = self.coords
        if vswgse: _vswgse = self.vswgse
        if not datetime is None: _datetime = self.datetime

        # Pass position if new
        if lat: self.lat = lat
        lat = self.lat
        if lon: self.lon = lon
        lon = self.lon
        if rho: self.rho = rho
        rho = self.rho
        if not datetime is None: self.datetime = datetime
        datetime = self.datetime

        # Set necessary parameters if new
        if coords: self.coords = coords
        coords = self.coords
        if not datetime is None: self.datetime = datetime
        datetime = self.datetime
        if vswgse: self.vswgse = vswgse
        vswgse = self.vswgse
        if pdyn: self.pdyn = pdyn
        pdyn = self.pdyn
        if dst: self.dst = dst
        dst = self.dst
        if byimf: self.byimf = byimf
        byimf = self.byimf
        if bzimf: self.bzimf = bzimf
        bzimf = self.bzimf

        # Test that everything is in order, if not revert to existing values
        iTest = self.__test_valid__()
        if not iTest:
            if lat: self.lat = _lat
            if lon: _self.lon = lon
            if rho: self.rho = _rho
            if coords: self.coords = _coords
            if vswgse: self.vswgse = _vswgse
            if not datetime is None: self.datetime = _datetime

        # Declare the same Re as used in Tsyganenko models [km]
        Re = 6371.2

        # Initialize trace array
        self.l = zeros(len(lat))
        self.xTrace = zeros((len(lat), 2 * lmax))
        self.yTrace = self.xTrace.copy()
        self.zTrace = self.xTrace.copy()
        self.xGsw = self.l.copy()
        self.yGsw = self.l.copy()
        self.zGsw = self.l.copy()
        self.latNH = self.l.copy()
        self.lonNH = self.l.copy()
        self.rhoNH = self.l.copy()
        self.latSH = self.l.copy()
        self.lonSH = self.l.copy()
        self.rhoSH = self.l.copy()

        # And now iterate through the desired points
        for ip in xrange(len(lat)):
            # This has to be called first
            tsygFort.recalc_08(datetime[ip].year,
                               datetime[ip].timetuple().tm_yday,
                               datetime[ip].hour, datetime[ip].minute,
                               datetime[ip].second, vswgse[0], vswgse[1],
                               vswgse[2])

            # Convert lat,lon to geographic cartesian and then gsw
            r, theta, phi, xgeo, ygeo, zgeo = tsygFort.sphcar_08(
                rho[ip] / Re, radians(90. - lat[ip]), radians(lon[ip]), 0., 0.,
                0., 1)
            if coords.lower() == 'geo':
                xgeo, ygeo, zgeo, xgsw, ygsw, zgsw = tsygFort.geogsw_08(
                    xgeo, ygeo, zgeo, 0., 0., 0., 1)
            self.xGsw[ip] = xgsw
            self.yGsw[ip] = ygsw
            self.zGsw[ip] = zgsw

            # Trace field line
            inmod = 'IGRF_GSW_08'
            exmod = 'T96_01'
            parmod = [pdyn, dst, byimf, bzimf, 0, 0, 0, 0, 0, 0]
            # First towards southern hemisphere
            maptoL = [-1, 1]
            for mapto in maptoL:
                xfgsw, yfgsw, zfgsw, xarr, yarr, zarr, l = tsygFort.trace_08(
                    xgsw, ygsw, zgsw, mapto, dsmax, err, rmax, rmin, 0, parmod,
                    exmod, inmod, lmax)

                # Convert back to spherical geographic coords
                xfgeo, yfgeo, zfgeo, xfgsw, yfgsw, zfgsw = tsygFort.geogsw_08(
                    0., 0., 0., xfgsw, yfgsw, zfgsw, -1)
                geoR, geoColat, geoLon, xgeo, ygeo, zgeo = tsygFort.sphcar_08(
                    0., 0., 0., xfgeo, yfgeo, zfgeo, -1)

                # Get coordinates of traced point
                if mapto == 1:
                    self.latSH[ip] = 90. - degrees(geoColat)
                    self.lonSH[ip] = degrees(geoLon)
                    self.rhoSH[ip] = geoR * Re
                elif mapto == -1:
                    self.latNH[ip] = 90. - degrees(geoColat)
                    self.lonNH[ip] = degrees(geoLon)
                    self.rhoNH[ip] = geoR * Re

                # Store trace
                if mapto == -1:
                    self.xTrace[ip, 0:l] = xarr[l - 1::-1]
                    self.yTrace[ip, 0:l] = yarr[l - 1::-1]
                    self.zTrace[ip, 0:l] = zarr[l - 1::-1]
                elif mapto == 1:
                    ind = int(self.l[ip])
                    self.xTrace[ip, ind:ind + l] = xarr[0:l]
                    self.yTrace[ip, ind:ind + l] = yarr[0:l]
                    self.zTrace[ip, ind:ind + l] = zarr[0:l]
                self.l[ip] += l

        # Resize trace output to more minimum possible length
        ind = int(self.l.max())
        self.xTrace = self.xTrace[:, 0:ind]
        self.yTrace = self.yTrace[:, 0:ind]
        self.zTrace = self.zTrace[:, 0:ind]
示例#3
0
    def trace_drift(self):
        # Input parameters
        # 1- Date and time of the injection
        #-------------------------------------------------------------------------------#
        _date = self.date
        _imod = self.imod        # magnetic field model: 0=dipole, 1=T96_01, 2=T01_1, 3=T04_s
        _ipot = self.ipot        # electric field model: 1=Weimer, 2=CIMI 
        _itrace = self.itrace      # 1=forward, -1=backward tracing
        _tsec0 = self.tsec       # initial time in second
        _tend = self.tend     # end time in second
        _ro = self.ro          # initial radial distance in RE
        _mlt = self.mlt         # initial mlt in hour
        _ekev0 = self.ekev0      # initial energy in keV
        _Kin = 0         # K index, 0=equatorially mirroring (reserved, not used now)
        _ion= self.ion          # 1=ion, -1=electron
        _tf = self.tf         # time resolution in seconds in updating omni parameters
        #-------------------------------------------------------------------------------#
        ### Main trace_drift subroutine 
        pi=np.pi
        dra=_itrace*0.5*pi/180.           # drift path tracing step size in radian
        iprint=1                         # print result every iprint steps
        re=6.371e6                       # earth's radius (m)
        if (_ion == 1): Eo=9.38269e5      # proton rest energy
        if (_ion == -1): Eo=511.          # electron rest energy
        Eo2=Eo*Eo
        pc_sq=(_ekev0+Eo)**2-Eo2         # (pc)^2 in keV^2
        latmax=72.*pi/180.              # max allowable latitude at the ionosphere
        reqmax=10.                      # max allowable equatorial distance
        istepmax=3000                   # max allowable istep
        rc=1.
        #Find dipole moment
        iyear = _date.year
        dts = spt.Ticktock(_date)
        iday = dts.DOY
        tsec0_dt = _date+timedelta(seconds=_tsec0)
        parmod,nsw,vxgse,vygse,vzgse = self.TsyParmod(_date+timedelta(seconds=_tsec0),_imod)# vy and vz are 0 to ensure GSM coordinate system
        tsygFort.recalc_08(iyear,iday,tsec0_dt.hour,tsec0_dt.minute,tsec0_dt.second,vxgse,vygse,vzgse)
        GGG=tsygFort.geopack2.g
        HHH=tsygFort.geopack2.h
        DIPMOM=np.sqrt(GGG[1]**2+GGG[2]**2+HHH[2]**2)   # DIPMOM in (nT RE^3)
        xme=DIPMOM*re**3*1.e-9                       # dipole moment in (T m^3)
        #xme = np.exp(36.58626097)
        # Find the initial ionospheric projection (along field line) point
        phi=_mlt*pi/12.               
        xeq=-_ro*np.cos(phi)              # +x --> Sun
        yeq=-_ro*np.sin(phi)
        zeq=0.
        lati,mlti = self.mapping(_imod,parmod,xeq,yeq,zeq,0,0,1)
        x0 = np.zeros(2)
        x0[0]=lati                 # latitude in radian
        x0[1]=mlti                 # local time in radian

        # find Bmag, sinA at the initial position and the invariant pcy2B
        bx,by,bz,Bmag=self.Tsy_w_dip(_imod,parmod,xeq,yeq,zeq)
        _sinA=self.sinA
        #ipdb.set_trace()
        self.pcy2B=pc_sq*_sinA*_sinA/Bmag  # First invariant, Bmag = B at equator
        self.K = self.KofAlpha(np.arcsin(_sinA),lati,mlti,_imod,parmod) # Second invariant K
        # Print the initial condition
        pitchA=np.arcsin(_sinA)*180./pi
        Lshell=rc/(np.cos(lati))**2
        mlti_d=mlti*12./pi              # mlt at ionosphere in hour
        print('%i %i %i %i %i %4.2f ! iyear,iday,imod,ipot,ion,tf' %(iyear,iday,_imod,_ipot,_ion,_tf))
        print('  tsec             Dst     Lshell     mlti        ro      mlto      ekeV   PA    Vsw   Pdyn')
        print('%6.2f %7.0f %9.3f %9.3f  %9.3f %6.3f  %6.1f %6.2f' %(_tsec0,parmod[1],Lshell,mlti_d,_ro,_mlt,_ekev0,pitchA))
        # ipdb.set_trace()
        # Start drift path tracing
        tsec=_tsec0
        istep=0
        iexit=0
        lastprint=0
        iexit=0
        vswi=vxgse
        xnswi = nsw
        Dst0 = parmod[1]
        xeq0=0;yeq0=0;zeq0=0
        ##
        roarr=np.zeros(istepmax)
        mltoarr=np.zeros(istepmax)
        tsecarr=np.zeros(istepmax)
        Eoarr=np.zeros(istepmax)
        ## Start debugging 
        while (iexit != 1):
            #ipdb.set_trace() 
            xend,dtsec=self.rk4(_imod,_ipot,parmod,vswi,xnswi,_ion,dra,Eo,xme,x0,_sinA)
            if (_sinA!=1):
                _Alpha,_Bmag = self.AlphaOfK(self.K,xend[0],xend[1],_imod,parmod)
                _sinA = np.sin(_Alpha)
            # update istep, tsec, Bmag
            istep=istep+1
            tsec=tsec+dtsec
            xeq,yeq,zeq,iout=self.mapping(_imod,parmod,0,0,0,xend[0],xend[1],-1)
            req=np.sqrt(xeq*xeq+yeq*yeq)
            # test for exit or continue
            if (istep==istepmax): iexit=1
            if (iout==1): iexit=1            
            if (xend[0]>=latmax): 
                iexit=1
                print('Warning: xend[0]>=latmax')
            if (req>=reqmax): iexit=1
            if ((_itrace==1) and (tsec>=_tend)): iexit=1            
            if ((_itrace==-1) and (tsec<=_tend)): iexit=1
            # Reasign values if iexit.eq.1
            if (iexit==1):
                #ipdb.set_trace()
                tsec=tsec-dtsec
                xend=x0
                parmod[1]=Dst0
                xeq=xeq0
                yeq=yeq0
                zeq=zeq0
                req=np.sqrt(xeq*xeq+yeq*yeq)
                if (tsec>=tprint): lastprint=1
            # print result every iprint step and at the end of the trace
            if ((np.mod(istep,iprint)==0) or (lastprint==1)):
                bx,by,bz,Bmag = self.Tsy_w_dip(_imod,parmod,xeq,yeq,zeq)
                ipdb.set_trace()
                pc_sq=self.pcy2B*Bmag/_sinA/_sinA
                ekev=np.sqrt(pc_sq+Eo2)-Eo
                pitchA=np.arcsin(_sinA)*180./pi
                Lshell=rc/(np.cos(xend[0]))**2
                mlti_d=xend[1]*12./pi          # mlt at ionosphere in hour
                phi=np.arctan2(yeq,xeq)
                mlteq=phi*12./pi+12.
                tprint=tsec
                print('%6.2f %7.0f %9.3f %9.3f  %9.3f %6.3f  %6.1f %6.2f %7.2f %6.4f'\
                      %(tsec,parmod[1],Lshell,mlti_d,req,mlteq,ekev,pitchA,vswi,parmod[0]))
                roarr[istep-1]=req ## variables for ploting
                mltoarr[istep-1]=mlteq
                tsecarr[istep-1]=tsec
                Eoarr[istep-1]=ekev
            # Save values 
            Dst0=parmod[1]
            xeq0=xeq
            yeq0=yeq
            zeq0=zeq
            # Update x0 and Tsyganenko parmod
            x0=xend
            if istep==1: dstep = int(_tf/dtsec) # choose an aproximate dt step for changing SW parameters
            if np.mod(istep,dstep)==0: 
                parmod,xnswi,vswi,vygse,vzgse = self.TsyParmod(_date+timedelta(seconds=tsec),_imod)
        return tsecarr,mltoarr,roarr,Eoarr,istep
示例#4
0
    def trace(self, lat=None, lon=None, rho=None, coords=None, datetime=None,
        vswgse=None, pdyn=None, dst=None, byimf=None, bzimf=None,
        lmax=5000, rmax=60., rmin=1., dsmax=0.01, err=0.000001):
        """
|   See tsygTrace for a description of each parameter
|   Any unspecified parameter default to the one stored in the object
|   Unspecified lmax, rmax, rmin, dsmax, err has a set default value
|
|   Written by Sebastien 2012-10
        """
        from numpy import radians, degrees, zeros

        # Store existing values of class attributes in case something is wrong
        # and we need to revert back to them
        if lat: _lat = self.lat
        if lon: _lon = self.lon
        if rho: _rho = self.rho
        if coords: _coords = self.coords
        if vswgse: _vswgse = self.vswgse
        if not datetime==None: _datetime = self.datetime

        # Pass position if new
        if lat: self.lat = lat
        lat = self.lat
        if lon: self.lon = lon
        lon = self.lon
        if rho: self.rho = rho
        rho = self.rho
        if not datetime==None: self.datetime = datetime
        datetime = self.datetime

        # Set necessary parameters if new
        if coords: self.coords = coords
        coords = self.coords
        if not datetime==None: self.datetime = datetime
        datetime = self.datetime
        if vswgse: self.vswgse = vswgse
        vswgse = self.vswgse
        if pdyn: self.pdyn = pdyn
        pdyn = self.pdyn
        if dst: self.dst = dst
        dst = self.dst
        if byimf: self.byimf = byimf
        byimf = self.byimf
        if bzimf: self.bzimf = bzimf
        bzimf = self.bzimf

        # Test that everything is in order, if not revert to existing values
        iTest = self.__test_valid__()
        if not iTest: 
            if lat: self.lat = _lat
            if lon: _self.lon = lon
            if rho: self.rho = _rho
            if coords: self.coords = _coords 
            if vswgse: self.vswgse = _vswgse
            if not datetime==None: self.datetime = _datetime

        # Declare the same Re as used in Tsyganenko models [km]
        Re = 6371.2
        
        # Initialize trace array
        self.l = zeros(len(lat))
        self.xTrace = zeros((len(lat),2*lmax))
        self.yTrace = self.xTrace.copy()
        self.zTrace = self.xTrace.copy()
        self.xGsw = self.l.copy()
        self.yGsw = self.l.copy()
        self.zGsw = self.l.copy()
        self.latNH = self.l.copy()
        self.lonNH = self.l.copy()
        self.rhoNH = self.l.copy()
        self.latSH = self.l.copy()
        self.lonSH = self.l.copy()
        self.rhoSH = self.l.copy()

        # And now iterate through the desired points
        for ip in xrange(len(lat)):
            # This has to be called first
            tsygFort.recalc_08(datetime[ip].year,datetime[ip].timetuple().tm_yday,
                                datetime[ip].hour,datetime[ip].minute,datetime[ip].second,
                                vswgse[0],vswgse[1],vswgse[2])

            # Convert lat,lon to geographic cartesian and then gsw
            r, theta, phi, xgeo, ygeo, zgeo = tsygFort.sphcar_08(
                                                    rho[ip]/Re, radians(90.-lat[ip]), radians(lon[ip]),
                                                    0., 0., 0.,
                                                    1)
            if coords.lower() == 'geo':
                xgeo, ygeo, zgeo, xgsw, ygsw, zgsw = tsygFort.geogsw_08(
                                                            xgeo, ygeo, zgeo,
                                                            0. ,0. ,0. ,
                                                            1)
            self.xGsw[ip] = xgsw
            self.yGsw[ip] = ygsw
            self.zGsw[ip] = zgsw

            # Trace field line
            inmod = 'IGRF_GSW_08'
            exmod = 'T96_01'
            parmod = [pdyn, dst, byimf, bzimf, 0, 0, 0, 0, 0, 0]
            # First towards southern hemisphere
            maptoL = [-1, 1]
            for mapto in maptoL:
                xfgsw, yfgsw, zfgsw, xarr, yarr, zarr, l = tsygFort.trace_08( xgsw, ygsw, zgsw,
                                                                mapto, dsmax, err, rmax, rmin, 0,
                                                                parmod, exmod, inmod,
                                                                lmax )

                # Convert back to spherical geographic coords
                xfgeo, yfgeo, zfgeo, xfgsw, yfgsw, zfgsw  = tsygFort.geogsw_08(
                                                                    0. ,0. ,0. ,
                                                                    xfgsw, yfgsw, zfgsw,
                                                                    -1)
                geoR, geoColat, geoLon, xgeo, ygeo, zgeo = tsygFort.sphcar_08(
                                                                    0., 0., 0.,
                                                                    xfgeo, yfgeo, zfgeo,
                                                                    -1)

                # Get coordinates of traced point
                if mapto == 1:
                    self.latSH[ip] = 90. - degrees(geoColat)
                    self.lonSH[ip] = degrees(geoLon)
                    self.rhoSH[ip] = geoR*Re
                elif mapto == -1:
                    self.latNH[ip] = 90. - degrees(geoColat)
                    self.lonNH[ip] = degrees(geoLon)
                    self.rhoNH[ip] = geoR*Re
                    
                # Store trace
                if mapto == -1:
                    self.xTrace[ip,0:l] = xarr[l-1::-1]
                    self.yTrace[ip,0:l] = yarr[l-1::-1]
                    self.zTrace[ip,0:l] = zarr[l-1::-1]
                elif mapto == 1:
                    self.xTrace[ip,self.l[ip]:self.l[ip]+l] = xarr[0:l]
                    self.yTrace[ip,self.l[ip]:self.l[ip]+l] = yarr[0:l]
                    self.zTrace[ip,self.l[ip]:self.l[ip]+l] = zarr[0:l]
                self.l[ip] += l

        # Resize trace output to more minimum possible length
        self.xTrace = self.xTrace[:,0:self.l.max()]
        self.yTrace = self.yTrace[:,0:self.l.max()]
        self.zTrace = self.zTrace[:,0:self.l.max()]