def lon_lat_r(body, time, earth_radius=6371e3): """ Use SPICE software to get longitude and latitude of the point on Earth at which <body> is in zenith and the distance between the barycenters of Earth and <body> at a specified <time> (in UTC). We're pretending the earth is a sphere here, as is commonly done in tidal studies (and presumably is done in the ocean model this is fed into). Input: body - SPICE name of the body (e.g. "SUN" or "MOON") time - date and time in datetime format (UTC) earth_radius - radius of the earth (default 6371e3 m) Output: lon, lat - longitude and latitude at which <body> is in zenith r - range of the body (distance between barycenters) """ # convert UTC time to ephemeris time time = spice.str2et(str(time) + " UTC") # get position in rectangular coordinate system (body frame of Earth) pos_rec, _ = spice.spkpos(body, time, "ITRF93", "NONE", "EARTH") # transform to geodetic coordinates assuming zero flatness (to get lat/lon) pos_geo = spice.recgeo(pos_rec, earth_radius / 1e3, 0) # transform to range, right ascension, declination (to get range) pos_rad = spice.recrad(pos_rec) # isolate coordinates we'll need (and convert from km to m) lon = pos_geo[0] lat = pos_geo[1] r = pos_rad[0] * 1e3 return lon, lat, r
def producegeometrylamda(et, sv, when): [TGO, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.target) [MEX, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.obs) dist = math.floor(spice.vdist(TGO, MEX)) print(dist) # NEED TO PRODUCE VECTOR OF SZA AND HEIGHTS THAT ARE 'DIST' LONG [13242.9 m] *comp expensive # start by making DIST length vector, 3 height, for every meter from mex to tgo # MAYBE FIND THE UNIT VECTOR AND ADD ONE IN ITS DIRECTION!! angleseparation = (spice.vsep(MEX, TGO)) * (180 / math.pi ) # angle taken a mars center initialangle = (spice.vsep(-MEX, (TGO - MEX))) * ( 180 / math.pi ) # angle taken at mars-MEX-tgo, that points to tgo. needed for the bending functions original starting angle #script needs to work via periods of ray and not meters. [totalperiods is the main iterable, not meters] vacuumwavelength = constants.c / 437.1e6 scale = 1 # scale =10, means we are itertating per 100 wavelenghts instead of 1000 (default 1000 because SPICE works in km) wavelengthsinameter = 1 / vacuumwavelength a = wavelengthsinameter * dist * scale total1000periods = math.floor(a) # ~that many thousands of periods remainingdistance = (vacuumwavelength / scale) * ( (wavelengthsinameter * dist * scale) - total1000periods ) # quanitfy the remaineder, this distance can # added later, this remaining portion is extreamly high altitude (near Target) and has no refractive effects. therfor simply added (km) #total1000periods = total1000periods.astype(int) sc2sc = TGO - MEX norm = np.linalg.norm(sc2sc) unitsc2sc = sc2sc / (norm * vacuumwavelength * scale ) #this needs to shrink if the repeatable expands points = np.empty([3, total1000periods]) sza = np.empty([1, total1000periods]) marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] # find direction of sun, it will not change much during the occultation. so only calc it once [SUN, _] = spice.spkpos(sv.front, et, sv.fframe, 'NONE', 'SUN') for i in range(total1000periods): point = MEX + ( i * unitsc2sc ) #move along ray, 1000 wavelength distance at a time (685 m). but unitsc2sc is in km... sza[0, i] = spice.vsep(SUN, point) points[:, i] = spice.recgeo(point, equatorialradii, flatteningcoefficient) points[0, i] = (points[0, i] * (-180 / math.pi)) points[1, i] = (points[1, i] * (-180 / math.pi)) print((i / math.floor(total1000periods)) * 100) ray = np.concatenate((points, sza), axis=0) print('stop here') return ray, dist, angleseparation, initialangle, total1000periods, vacuumwavelength, remainingdistance
def producegeometrymeter(et, sv, when): [TGO, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.target) [MEX, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.obs) dist = math.floor(spice.vdist(TGO, MEX)) print(dist) # NEED TO PRODUCE VECTOR OF SZA AND HEIGHTS THAT ARE 'DIST' LONG [13242.9 m] *comp expensive # start by making DIST length vector, 3 height, for every meter from mex to tgo # MAYBE FIND THE UNIT VECTOR AND ADD ONE IN ITS DIRECTION!! angleseparation = (spice.vsep(MEX, TGO)) # angle taken a mars center initialangle = (spice.vsep(-MEX, (TGO - MEX))) * ( 180 / math.pi ) # angle taken at mars-MEX-tgo, that points to tgo. needed for the bending functions original starting angle #script needs to work via periods of ray and not meters. [totalperiods is the main iterable, not meters] scale = 0.1 # scale =10, means we are itertating per 100 wavelenghts instead of 1000 (default 1000 because SPICE works in km) dist = math.floor(dist) # km sc2sc = TGO - MEX norm = np.linalg.norm(sc2sc) unitsc2sc = sc2sc / norm #this needs to shrink if the repeatable expands points = np.empty([3, dist]) sza = np.empty([1, dist]) angleprogression = np.empty([1, dist]) xyzpoints = np.zeros([3, dist]) marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] # find direction of sun, it will not change much during the occultation. so only calc it once [SUN, _] = spice.spkpos(sv.front, et, sv.fframe, 'NONE', 'SUN') for i in range(dist): xyzpoint = MEX + ( i * unitsc2sc ) #move along ray, 1000 wavelength distance at a time (685 m). but unitsc2sc is in km... xyzpoints[:, i] = xyzpoint sza[0, i] = spice.vsep(SUN, xyzpoint) angleprogression[0, i] = (spice.vsep(xyzpoint, MEX)) * (180 / math.pi) points[:, i] = spice.recgeo(xyzpoint, equatorialradii, flatteningcoefficient) points[0, i] = (points[0, i] * (-180 / math.pi)) points[1, i] = (points[1, i] * (-180 / math.pi)) print((i / math.floor(dist)) * 100) ray = np.concatenate((points, sza), axis=0) #plt.plot(angleprogression[0,:], ray[2,:]) #plt.show() # ray is in lat/lon/alt + sza and xyzpoints is cartesian, both describe the same thing return ray, dist, unitsc2sc, angleseparation, initialangle, MEX, TGO, xyzpoints, angleprogression
def producegeometrymeter(et, sv, when): [TGO, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.target) [MEX, _] = spice.spkpos(sv.front, et - when, sv.fframe, 'NONE', sv.obs) dist = math.floor(spice.vdist(TGO, MEX)) angleseparation = (spice.vsep(MEX, TGO)) # angle taken a mars center initialangle = (spice.vsep(-MEX, (TGO - MEX))) * ( 180 / math.pi ) # angle taken at mars-MEX-tgo, that points to tgo. needed for the bending functions original starting angle #script needs to work via periods of ray and not meters. [totalperiods is the main iterable, not meters] sc2sc = TGO - MEX norm = np.linalg.norm(sc2sc) unitsc2sc = sc2sc / norm #this needs to shrink if the repeatable expands points = np.empty([3, dist]) sza = np.empty([1, dist]) angleprogression = np.empty([1, dist]) xyzpoints = np.zeros([3, dist]) marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] # find direction of sun, it will not change much during the occultation. so only calc it once [SUN, _] = spice.spkpos(sv.front, et, sv.fframe, 'NONE', 'SUN') for i in range(dist): xyzpoint = MEX + ( i * unitsc2sc ) #move along ray, 1000 wavelength distance at a time (685 m). but unitsc2sc is in km... xyzpoints[:, i] = xyzpoint sza[0, i] = spice.vsep(SUN, xyzpoint) angleprogression[0, i] = (spice.vsep(xyzpoint, MEX)) * (180 / math.pi) points[:, i] = spice.recgeo(xyzpoint, equatorialradii, flatteningcoefficient) points[0, i] = (points[0, i] * (-180 / math.pi)) points[1, i] = (points[1, i] * (-180 / math.pi)) ray = np.concatenate((points, sza), axis=0) # important for when sza is included #plt.plot(angleprogression[0,:], ray[2,:]) #plt.show() # ray is in lat/lon/alt + sza and xyzpoints is cartesian, both describe the same thing return initialangle, MEX, TGO, xyzpoints
def lon_lat_r(body, time): """ Use SPICE software to get - longitude and latitude of <body>'s subsolar point, or the coordinates at which <body> is in zenith (or point 'Q' in Munk and Cartwright 1966's figure 13), and - the distance between the barycenters of Earth and <body> at a specified <time> (in UTC). The input <body> is a string like "SUN" or "MOON", and <time> is a datestring with format 'yyyy-mm-dd hh:mm:ss' """ # The equivalent spherical radius of earth. earth_radius = 6371e3 # Convert UTC time to ephemeris time in seconds past J2000 TDB. time = spice.str2et(str(time) + " UTC") # Get the position in km in a rectangular coordinate system whose # origin lies at the center of "EARTH", with no time-correction. pos_rec, _ = spice.spkpos(body, time, "ITRF93", "NONE", "EARTH") # Calculate the lat, lon position on an unflattened sphere with # Earth's average radius on a line passing from pos_rec # to (0, 0, 0) (which is the Earth's center). flatten_coeff = 0 pos_geo = spice.recgeo(pos_rec, earth_radius/1e3, flatten_coeff) # Transform pos_rec to range (in km), right ascension, declination. # The 'range' is the 'r' we seek: the distance between the center # of the body and the center of the Earth. pos_rad = spice.recrad(pos_rec) # Isolate coordinates we'll need and convert range from km to m lon = pos_geo[0] lat = pos_geo[1] r = pos_rad[0]*1e3 return lon, lat, r
def geometry(et, bsight, target, frame, sensor, observer=''): if not observer: observer = sensor # Time tag [UTC] # pixel id [(x,y)] # corner id [(x,y)] # Requested geometry # lat lon intersection (planetocentric) # lat lon subspacecraft # lat lon subsolar # target distance intersection # target angular diameter # local solar time intersection # phase angle intersection # emission angle intersection # incidence angle intersection # # We retrieve the camera information using GETFOV. More info available: # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/getfov_c.html # sensor_id = spiceypy.bodn2c(sensor) (shape, sensor_frame, ibsight, vectors, bounds) = spiceypy.getfov(sensor_id, 100) visible = spiceypy.fovtrg(sensor, target, 'ELLIPSOID', frame, 'LT+S', observer, et) if not visible: return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 tarid = spiceypy.bodn2c(target) n, radii = spiceypy.bodvrd(target, 'RADII', 3) re = radii[0] rp = radii[2] f = (re - rp) / re try: # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html # # For each pixel we compute the possible intersection with the target, if # the target is intersected we then compute the illumination angles. We # use the following SPICE APIs: SINCPT and ILLUMF # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/illumf_c.html # (spoint, trgepc, srfvec) = \ spiceypy.sincpt('ELLIPSOID', target, et, frame, 'LT+S', observer, sensor_frame, bsight) (tarlon, tarlat, taralt) = spiceypy.recgeo(spoint, re, f) tardis = spiceypy.vnorm(srfvec) # # Angular diameter # tarang = np.degrees( 2 * np.arctan(max(radii) / spiceypy.vnorm(spoint + srfvec))) # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/illumf_c.html # (trgenpc, srfvec, phase, incdnc, emissn, visiblef, iluminatedf) = \ spiceypy.illumf('ELLIPSOID', target, 'SUN', et, frame, 'LT+S', observer, spoint) phase *= spiceypy.dpr() incdnc *= spiceypy.dpr() emissn *= spiceypy.dpr() # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/et2lst_c.html # # VARIABLE I/O DESCRIPTION # -------- --- -------------------------------------------------- # et I Epoch in seconds past J2000 epoch. # body I ID-code of the body of interest. # lon I Longitude of surface point (RADIANS). # type I Type of longitude "PLANETOCENTRIC", etc. # timlen I Available room in output time string. # ampmlen I Available room in output `ampm' string. # hr O Local hour on a "24 hour" clock. # mn O Minutes past the hour. # sc O Seconds past the minute. # time O String giving local time on 24 hour clock. # ampm O String giving time on A.M./ P.M. scale. (hr, mn, sc, ltime, ampm) = \ spiceypy.et2lst(et, tarid, tarlon, 'PLANETOCENTRIC', 80, 80) # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subpnt_c.html # # Variable I/O Description # -------- --- -------------------------------------------------- # method I Computation method. # target I Name of target body. # et I Epoch in TDB seconds past J2000 TDB. # fixref I Body-fixed, body-centered target body frame. # abcorr I Aberration correction flag. # obsrvr I Name of observing body. # spoint O Sub-observer point on the target body. # trgepc O Sub-observer point epoch. # srfvec O Vector from observer to sub-observer point # (spoint, trgepc, srfev) = \ spiceypy.subpnt('INTERCEPT/ELLIPSOID', target, et, frame, 'LT+S', observer) (sublon, sublat, subalt) = spiceypy.recgeo(spoint, re, f) # # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subslr_c.html # # Variable I/O Description # -------- --- -------------------------------------------------- # method I Computation method. # target I Name of target body. # et I Epoch in ephemeris seconds past J2000 TDB. # fixref I Body-fixed, body-centered target body frame. # abcorr I Aberration correction. # obsrvr I Name of observing body. # spoint O Sub-solar point on the target body. # trgepc O Sub-solar point epoch. # srfvec O Vector from observer to sub-solar point. # (spoint, trgepc, srfev) = \ spiceypy.subslr('INTERCEPT/ELLIPSOID', target, et, frame, 'LT+S', observer) (sunlon, sunlat, sunalt) = spiceypy.recgeo(spoint, re, f) return tarlon, tarlat, sublon, sublat, sunlon, sunlat, tardis, tarang, ltime, phase, emissn, incdnc except: return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
def flatbending(xyzpoints, initialangle, MEX, TGO, referencedirection): class SpiceVariables: obs = '-74' # NAIF code for MEX target = 'MARS ODYSSEY' # NAIF code for TGO ['EARTH'/'SUN'/ a groundstation etc] obsfrm = 'IAU_MARS' abcorr = 'NONE' crdsys = 'LATITUDINAL' coord = 'LATITUDE' stepsz = 100.0 # Check every 300 seconds if there is an occultation MAXILV = 100000 #Max number of occultations that can be returned by gfoclt bshape = 'POINT' fshape = 'DSK/UNPRIORITIZED' front = 'MARS' fframe = 'IAU_MARS' TFMT = 'YYYY-MM-DD HR:MN:SC' # Format that Cosmographia understands sv = SpiceVariables() #form a coordinate system where tgo is @ y=0 and x= (5000 +norm), Mar's Barrycenter being @ [5000,0] subgroupsize = 1 #initialise non-global variables miniray = np.zeros(subgroupsize) raystep = np.zeros( (2, 100000000)) # create a large array to populate and then shrink later barry2mex = np.linalg.norm(MEX) barry2tgo = np.linalg.norm(TGO) #find the martian geomoerty so you can reliably find the altitude of a point marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] TGO = TGO + 0 MEX = MEX + 0 #force to be non-strided _, _, MEXalt = spice.recgeo(MEX, equatorialradii, flatteningcoefficient) _, _, TGOalt = spice.recgeo(TGO, equatorialradii, flatteningcoefficient) #the possition of MEX is found by assuming that it will be somewhere over the relative horizon from TGO # (meaning over θ = 90°), finding the angle between the MEX and TGO's negative vector, will give the coords of MEX MexRelativeElevation = spice.vsep(-TGO, MEX) #radians mex_y = barry2mex * np.sin(MexRelativeElevation) mex_x = barry2mex * np.cos(MexRelativeElevation) mex = np.array([0 - mex_x, mex_y]) tgo = np.array([0 + barry2tgo, 0]) barry = np.array([0, 0]) #to plot the non-refracted propogation, we must convert the 3d xyzpoints to 2d, we do this the same way we found the x&y for MEX # ,using the norm distance and sep from -TGO5 length = np.size(xyzpoints, 1) UnrefractedDistance = np.linalg.norm(xyzpoints[:, 0] - xyzpoints[:, -1]) #in km UnrefractedRay = np.zeros([2, length]) for i in range(length): #conversion to 2D point = xyzpoints[:, i] + 0 #need to put vector into temp variable as spice cant handle strided array inputs angle = spice.vsep(-TGO, point) norm = np.linalg.norm(point) point_x = norm * np.cos(angle) point_y = norm * np.sin(angle) UnrefractedRay[0, i] = 0 - point_x UnrefractedRay[1, i] = point_y #this will produce and angle that is likly not going to be exactly on #the original propagation path, you compare to this if there is a drifting error, as both this and the resultant refracted ray # have the same bias error. THIS ANGLE IS BENDING ANTICLOCKWISE IN THIS FRAME (BENDING UPWARDS) initialtheta = -(spice.vsep(MEX - TGO, MEX)) nicetohave = np.degrees(initialtheta) #THIS NEEDS TO VARY IF THERE IS AN OVERSHOOT unit = 1 # in km unitoriginal = unit rotationvector = np.array(((np.cos(initialtheta), -np.sin(initialtheta)), (np.sin(initialtheta), np.cos(initialtheta)))) #get unit vecotr of -MEX (then add this vecotr to MEX for each alt calcultation) unitmex = -mex / barry2mex #unit direction (2d) if referencedirection == [0, 0, 0]: initialdirection = unitmex.dot( rotationvector ) * unit #make a 2d vector coming from MEX YOU DO NOT KNOW WHAT WAY THIS IS ROTATING else: # if there is a value for the fed-back starting direction than use this as the first firection initialdirection = referencedirection iterationcount = 0 #while iterationcount<100: #print( "Finding Bending Angle (", str(iterationcount) ,"% Complete)") errorstore = np.zeros((11, 100000)) S = np.zeros(20000) #IF REFERCEDRECTION==0 DO NORMAL, IF /= INCLUDE THIS AS THE FIRST DIRECTION. while iterationcount < 10: tic = timer.perf_counter() if iterationcount == 0: direction = initialdirection else: missangle = missangle / 1 missrotationvector = np.array( ((np.cos(missangle), -np.sin(missangle)), (np.sin(missangle), np.cos(missangle)))) direction = initialdirection.dot(missrotationvector) #check the differecne between the initial and the direction, see if the same for both CHECK_ME = direction - initialdirection initialdirection = direction turningcounter = 0 stage = 0 t = 0 unit = unitoriginal #with tqdm(total = mex[1], desc = "Progress", leave=False) as pbar: while stage < 2: #==0first unit, so move two units. ==1 propergate step by step. ==2 exit and analyse entire path #take the alt at 10 possitions across this unit #lets get a quick calculated for the magnitude of the direction MAAAAG = np.linalg.norm(direction) # this should = unit if stage == 0: for k in range(subgroupsize): #this starts with 0 point = mex + ((k + 1) * (direction / subgroupsize)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) miniray[k] = np.linalg.norm( point) - 3389 #average radii of mars N0 = findrefractivity(miniray, subgroupsize) raystep[:, t] = point #save the last location t = t + 1 stage = stage + 1 if stage == 1: for k in range(subgroupsize): point = raystep[:, t - 1] + ( (k + 1) * (direction / subgroupsize) ) #am i double counting the end of the last and the start of the next? #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) #THIS ONLY WORKS IN 3D # IMPLEMENTING MARS AS A SIMPLE CIRCLE OF AVERAGE 3389 KM RADIUS, !THIS WILL BE UPDATED TO ELLIPSE! miniray[k] = np.linalg.norm(point) - 3389 raystep[:, t] = point #9 is the end of the unit, and refraction always happens relative to the center of refractivity, so rotate off this vector N1 = findrefractivity(miniray, subgroupsize) #IF THE Y VALUE DROPS BELOW 0, LOOP BACK WITH A STEP SIZE OF 1/10TH#################################################################<- HERE if point[1] < 0: #if the position drops below the x axis direction = direction / 10 #drop the step size unit = unit / 10 #stage = stage+1 #MAYBE SHRINK THE DIRECTION INSTEAD OF THE UNIT, IT DOESNT GET REINITIALED IN THIS WHILE LOOP # t is not incrememented so that it can loop back to the last position # , t-1 is the position just before crossing over into negative space if abs(point[1]) < 0.00001: # is it smaller than cm stage = stage + 1 #increase the stage value so the while loop is exited continue # #this section allows for better timing of the function, increment the progresbar by 1 if the current # #position goes one y-value lower # currenty = raystep[1,t] # progress[1] = mex[1] - currenty #this value will be increasing from 0 -> Mex height # increment = np.floor(progress[1])- np.floor(progress[0]) #only when # if increment ==1 : # pbar.update(1) # progress[0] = progress[1] if abs(N1) < 1e-20: #catch for precision errors S[t] = unit - ( N1 * unit ) # whilst neglegible N, Electric distance is can simply be inversly proportional to N t = t + 1 N0 = N1 continue #THE SECTION BELOW IS ONLY ACCESSED WHEN THE REFRACTIVTY IS ABOVE E-20 #print('Current Y possition is', currenty) #this is alt, so is ~3389 km smaller than the vector r = N0 / N1 #NEED MORE PRECISION numorator = N0 + 1 denominator = N1 + 1 rbending = numorator / denominator #average would just add 1 to total N # if t==5000: #only bend when there is a refractive gradient between consecutive air volumes[NO CHANGE IN DIRECTION] # t=t+1 # N0=N1 # continue #this section is only reached if a turning is going to happen # ,testing to see if there is 10 X less turing if the units are 10X smaller -TRUE TEST = float(rbending) if TEST != 1: turningcounter = turningcounter + 1 # !! NOW WITH PRECISION !! #find the angle between the unit (air volume) boarder and the current direction unitrotationaxis = raystep[:, t] / ( (np.linalg.norm(raystep[:, t])) * unit) #unitdirection = direction #MAYBE ALTERING UNITS WILL EFFECT THIS * OR / BY UNIT, CANT FIGURE OUT NOW, OK WHEN UNIT =1 DotProduct = np.dot((unitrotationaxis), direction) AngleofIncidence = (math.pi / 2) - np.arccos( DotProduct) #angle it enters the next air volume #simple snell law to find the bending angle (should be tiny angle) AngleofRefraction = np.arcsin(rbending * np.sin(AngleofIncidence)) # THIS IS NOT EXACTLY WHAT THE TURN IN DIRECTION IS, NEED TO THINK ABOUT rotateby = ((AngleofIncidence - AngleofRefraction) ) #+ve =clockwise, -ve=anticlockwise INCIDENCEDEGREES = np.degrees(AngleofIncidence) REFRACTIONDEGREES = np.degrees(AngleofRefraction) ROTATIONDEGREES = np.degrees(rotateby) #an if statement is required, if this if ROTATIONDEGREES > 1 or ROTATIONDEGREES < -1: print('stophere, u r bending to much') rotationvector = np.array( ((np.cos(rotateby), -np.sin(rotateby)), (np.sin(rotateby), np.cos(rotateby)))) direction = direction.dot(rotationvector) N0 = N1 #store N1 to calc electric distance S[t] = unit - (N1 * unit) t = t + 1 #pbar.refresh() unit_initial = initialdirection / np.linalg.norm(initialdirection) dot_product = np.dot(unit_initial, unitmex) FinalBendingAngle = np.arccos(dot_product) error = np.zeros(t) #print("Number of turns:", turningcounter) #error = swiftmain.finderror(raystep, UnrefractedRay) # also find the y-overshoot here miss = error # 1D along the abscissa #update for the miss angle, going to include miss in the ordinate #START EDITING HERE miss = point[0] - UnrefractedRay[0, -1] # X domain deltaX = UnrefractedRay[0, -1] #TGO X value deltaY = UnrefractedRay[ 1, 0] # this is the height of the whole 2d scene (both refract and unrefacted have the same height) unrefractedangle = np.arctan(deltaX / deltaY) refractedangle = np.arctan((deltaX + miss) / deltaY) missangle = refractedangle - unrefractedangle # if positive, then rotate clockwise #missangle = (np.arcsin(miss/UnrefractedDistance)) # this shouldnt work toc = timer.perf_counter() passingtime = toc - tic #print('miss =', format(miss*1000, '.5f') ,'m || Angle =', np.degrees(missangle) , # '° || Speed =',passingtime,' Sec \n', sep = " ", end= " ", flush =True) if abs(miss) < 1e-4: #is the miss smaller than 10 cm? #ploterrortraces(errorstore,t) break iterationcount = iterationcount + 1 #find the total bending angle at MEX for this final configuration #from the refractive profile from MEX ->TGO, calc the intergral of the change in wavelength to aquire doppler S = S[S != 0] ElectricDistance = ( np.sum(S) ) #N * wavelengths in a km (UNITS MUST BE KEPT THE SAME AS STEP-SIZE)[+ OVERSHOT BECAUSE IT IS A NEGATIVE VARIABLE ] return FinalBendingAngle, ElectricDistance, initialdirection #feedback the starting vector for speed
def producegeometrymeter(MEX, TGO): #maybe completly thin this out, you know this is moslty pointless, what does it actually make class SpiceVariables: obs = '-41' # NAIF code for MEX '-74' target = '-143' # NAIF code for TGO ['EARTH'/'SUN'/ a groundstation etc] 'MARS ODYSSEY' obsfrm = 'IAU_MARS' abcorr = 'NONE' crdsys = 'LATITUDINAL' coord = 'LATITUDE' stepsz = 1.0 # Check every [300] seconds if there is an occultation MAXILV = 100000 #Max number of occultations that can be returned by gfoclt bshape = 'POINT' fshape = 'DSK/UNPRIORITIZED' front = 'MARS' fframe = 'IAU_MARS' TFMT = 'YYYY-MM-DD HR:MN:SC' # Format that Cosmographia understands sv = SpiceVariables() #THIS COULD BE REMOVED # [TGO, _] = spice.spkpos(sv.front, et-when, sv.fframe, 'NONE', sv.target) # [MEX, _] = spice.spkpos(sv.front, et-when, sv.fframe, 'NONE', sv.obs) TGO = TGO + 0 MEX = MEX + 0 #force to be non-strided dist = math.floor(spice.vdist(TGO, MEX)) angleseparation = (spice.vsep(MEX, TGO)) # angle taken a mars center initialangle = (spice.vsep(-MEX, (TGO - MEX))) * ( 180 / math.pi ) # angle taken at mars-MEX-tgo, that points to tgo. needed for the bending functions original starting angle #script needs to work via periods of ray and not meters. [totalperiods is the main iterable, not meters] sc2sc = TGO - MEX norm = np.linalg.norm(sc2sc) unitsc2sc = sc2sc / norm #this needs to shrink if the repeatable expands points = np.empty([3, dist]) sza = np.empty([1, dist]) angleprogression = np.empty([1, dist]) xyzpoints = np.zeros([3, dist]) marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] # find direction of sun, it will not change much during the occultation. so only calc it once #[SUN, _] = spice.spkpos(sv.front, et, sv.fframe, 'NONE', 'SUN') for i in range(dist): xyzpoint = MEX + ( i * unitsc2sc ) #move along ray, 1000 wavelength distance at a time (685 m). but unitsc2sc is in km... xyzpoints[:, i] = xyzpoint #sza[0,i] = spice.vsep(SUN,xyzpoint) angleprogression[0, i] = (spice.vsep(xyzpoint, MEX)) * (180 / math.pi) points[:, i] = spice.recgeo(xyzpoint, equatorialradii, flatteningcoefficient) points[0, i] = (points[0, i] * (-180 / math.pi)) points[1, i] = (points[1, i] * (-180 / math.pi)) # ray = np.concatenate((points,sza), axis=0) # important for when sza is included #plt.plot(angleprogression[0,:], ray[2,:]) #plt.show() # ray is in lat/lon/alt + sza and xyzpoints is cartesian, both describe the same thing return initialangle, xyzpoints
def straight(ray, initialdirection, MEX, angleseparation, angleprogression, initialangle, xyzpoints, sv, interval): alt = ray[2, :] rawvector = xyzpoints[:, len(xyzpoints) - 1] - xyzpoints[:, 0] norm = np.linalg.norm(rawvector) rayunit = rawvector / norm interval = 1 marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] direction = initialdirection # everything must have a alt/ equiv dtheta poss = np.zeros([3, 10000]) dtheta = np.zeros([1, 10000]) possalt = np.zeros([1, 10000]) poss[:, 0] = MEX step = 10 # this will scale down to 0.001 (1m) miniray = np.zeros([3, step]) totalarcdistance = math.floor(alt[1] * angleseparation) # in km angleseparation = angleseparation * (180 / math.pi ) #we want in degrees now #NOTE TO SELF, AT FIRST THE DIFFERNCE IN N MIGHT BE TO SMALL IN THE HIGH ALT. MAYBE JUMP TO WHERE THE IONO BEGINS THEN START THIS LOOP for p in range( 100000 // step): #10,000 is the max distance, this will never be reached if p == 0: #You need a before n and after n so for the begining go forwards two to get a n0 and n1 point = poss[:, 0] + 0 # regeo needs non-strided arrays, this achieved by adding 0 (cheat) _, _, possalt[0, p] = spice.recgeo(point, equatorialradii, flatteningcoefficient) dtheta[0, p] = (spice.vsep(point, MEX)) * ( 180 / math.pi) #should give 0 degrees for i in range(step): point = poss[:, 0] + (interval * i * direction ) #make a small 'step' long 3d vector miniray[:, i] = spice.recgeo( point, equatorialradii, flatteningcoefficient) #(lon; lat; alt) n0 = findrefractivity(miniray, step) else: n0 = n1 for i in range(step): point = poss[:, p] + (interval * i * direction ) #make a small 'step' long 3d vector miniray[:, i] = spice.recgeo(point, equatorialradii, flatteningcoefficient) n1 = findrefractivity(miniray, step) #VECTOR CLACS [dont understand inuitivly, boiler plate] maybe this breaks if no r #SHOULD HIT THE IONO AT P=332, THIS MAKES SENSE r = n0 / n1 nextposs = poss[:, p] + ( interval * step * direction ) #move along this arc for 1km then recalc your position poss[:, p + 1] = nextposs #vsep doesnt allow strided arrays, so make a temp variable _, _, possalt[0, p + 1] = spice.recgeo(nextposs, equatorialradii, flatteningcoefficient) #need to have a catch for when the dtheta has been satisfied dtheta[0, p + 1] = (spice.vsep(nextposs, MEX)) * (180 / math.pi) if dtheta[0, p] > angleseparation: break #shorten the arrays to just contain the non-zeros values dtheta = dtheta[dtheta != 0] possalt = possalt[possalt != 0] straighterrors = np.zeros([1, p]) #ALT AND ANGLE PROGRESSION HAVE THE SAME LENGTH t = 0 alteration = alt[0] - possalt[0] for i in range(np.size(angleprogression, 1)): #up tp 6478 if t == 93: print('stophere') if angleprogression[0, i] > dtheta[t] and t < p: if t == 0: alteration = possalt[t] - alt[i] straightrayalt = alt[i] bendalt = possalt[t] error = straightrayalt - bendalt + alteration straighterrors[0, t] = error t = t + 1 else: continue return straighterrors
def bending(ray, initialdirection, MEX, angleseparation, angleprogression, initialangle, xyzpoints, sv): alt = ray[2, :] #THIS IS AN ATMOSPHERE TEST # ionoresidual = atmosphere.iono(ray,np.size(ray,1)) # neutralresidual = atmosphere.neutral(ray,np.size(ray,1)) # residual = 1 + (ionoresidual + neutralresidual) # plt.plot(angleprogression[0,:],residual[0,:]) # plt.title("Refractive Index through Propergation of Ray") # plt.xlabel("MEX -> Possition angle (degrees)") # plt.ylabel("Refractive Index") # plt.show() rawvector = xyzpoints[:, np.size(xyzpoints, 1) - 1] - xyzpoints[:, 0] norm = np.linalg.norm(rawvector) rayunit = rawvector / norm # THIS IS SLIGHTLY DIFFERENT TO THE RAY, THERE ARE PYTHON ROUNDING ERRORS marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] direction = rayunit # everything must have a alt/ equiv dtheta poss = np.zeros([3, 100000]) straightray = np.zeros([3, 100000]) poss[:, 0] = MEX straightray[:, 0] = MEX iterationmax = 0 miss = 0 glitchcount = 0 totalarcdistance = math.floor(alt[1] * angleseparation) # in km angleseparation = angleseparation * (180 / math.pi ) #we want in degrees now #NOTE TO SELF, AT FIRST THE DIFFERNCE IN N MIGHT BE TO SMALL IN THE HIGH ALT. MAYBE JUMP TO WHERE THE IONO BEGINS THEN START THIS LOOP while iterationmax <= 100: dtheta = np.zeros( 100000 ) # must be re-initialised as the vectors are filtered for 0 towards the end of this loop possalt = np.zeros(100000) straightpossalt = np.zeros(100000) #alter initial angle slightly according to miss #if miss ~0 dont alter angle, if miss +ve then bend down, (you will likely be bending up initially due to tropo) if miss == 0: print('.') # continue will make a 10-line loop with while else: angle = np.radians(miss * 0.03) # a miss of one km (0.3km = 2 degrees ) #alter the initail starting angle unitposs = MEX / np.linalg.norm( MEX) #vector going upwards radially if n0>n1 unitdirection = initialdirection / np.linalg.norm(initialdirection) rotationaxis = np.cross( unitposs, unitdirection ) #if direction is going rightwards, this rotation vector is going away from the viewer rotationvector = rotationaxis * angle #must be in degrees rotation = R.from_rotvec(rotationvector) direction = rotation.apply( initialdirection ) # produce the slightly re-angled new direction (tiny difference) step = 10 # this will scale down to 0.001 (1m) interval = 1 miniray = np.zeros([3, 10]) constantdirection = direction for p in range( 100000 // step): #10,000 is the max distance, this will never be reached if p == 0: #You need a before n and after n so for the begining go forwards two to get a n0 and n1 point = poss[:, 0] + 0 # regeo needs non-strided arrays, this achieved by adding 0 (cheat) _, _, possalt[p] = spice.recgeo(point, equatorialradii, flatteningcoefficient) dtheta[p] = (spice.vsep(point, MEX)) * ( 180 / math.pi) #should give 0 degrees for i in range(step): point = poss[:, 0] + (interval * i * direction ) #make a small 'step' long 3d vector miniray[:, i] = spice.recgeo( point, equatorialradii, flatteningcoefficient) #(lon; lat; alt) n0 = findrefractivity(miniray, step) elif p == 477: print('inspect from here') else: n0 = n1 for i in range(step): point = poss[:, p] + (interval * i * direction ) #make a small 'step' long 3d vector miniray[:, i] = spice.recgeo(point, equatorialradii, flatteningcoefficient) n1 = findrefractivity(miniray, step) #VECTOR CLACS [dont understand inuitivly, boiler plate] maybe this breaks if no r #SHOULD HIT THE IONO AT P=332, THIS MAKES SENSE r = n0 / n1 if r > 2 or r < 0.5: print('stop here cause neutral is causing huge bending') direction, hasglitched = newdirection(poss[:, p], direction, r, p) if hasglitched == 1: glitchcount = glitchcount + 1 nextposs = poss[:, p] + ( interval * step * direction ) #move along this arc for 1km then recalc your position nextstraightposs = straightray[:, p] + +(interval * step * constantdirection) straightray[:, p + 1] = nextstraightposs poss[:, p + 1] = nextposs #vsep doesnt allow strided arrays, so make a temp variable _, _, possalt[p + 1] = spice.recgeo(nextposs, equatorialradii, flatteningcoefficient) _, _, straightpossalt[p + 1] = spice.recgeo( nextstraightposs, equatorialradii, flatteningcoefficient) #need to have a catch for when the dtheta has been satisfied dtheta[p + 1] = (spice.vsep(nextposs, MEX)) * (180 / math.pi) if dtheta[p] > angleseparation: break #shorten the arrays to just contain the non-zeros values dtheta = dtheta[dtheta != 0] possalt = possalt[possalt != 0] straightpossalt = straightpossalt[straightpossalt != 0] errors = np.zeros([1, p]) straighterrors2 = np.zeros([1, p]) straightrayalt = np.zeros([1, p]) #ALT AND ANGLE PROGRESSION HAVE THE SAME LENGTH t = 0 alteration = alt[0] - possalt[0] for i in range(np.size(angleprogression, 1)): if angleprogression[0, i] > dtheta[t] and t < p: if t == 0: alteration = possalt[t] - alt[i] straightalteration = straightpossalt[t] - alt[i] straightrayalt[0, t] = alt[i] bendalt = possalt[t] iteratedstraightrayalt = straightpossalt[t] error = straightrayalt[0, t] - bendalt + alteration straighterrors2[0, t] = straightrayalt[ 0, t] - iteratedstraightrayalt + straightalteration errors[0, t] = error t = t + 1 else: continue straighterrors = straight(ray, direction, MEX, angleseparation, angleprogression, initialangle, xyzpoints, sv, interval) #if straighterrors2 == straighterrors, we can skip this straightcut = straighterrors[0, 0:p] #errors = errors[0] refractedcut = errors[0] # there is a glitch when the altitude becomes negative due to the spheriod not being considered. This is a patch to # remove the point of inflexion. Further inspection shows that glitches occured in low altitude and not negative altidue, the expnential # decay shape of the neutral refractivity profile led to small changes in alt, leading to huge changes in N, thus the refractive # ratio can exceed two and the ray can bend extreamly, veering it of the straight ray and into the martian core, meaning it never touches the 2nd ionsphere #This shouldnt be required once a good starting angle is found, only required for graphing early ray propogations (rays with the largest misses) # for i in range(p-1): # # if straightcut[i+1] < straightcut[i]:#inflexion # straightcut[i+1] = straightcut[i] + (straightcut[i]-straightcut[i-1]) # if refractedcut[i+1] < refractedcut[i]:#inflexion # refractedcut[i+1] = refractedcut[i] + (refractedcut[i]-refractedcut[i-1]) results = straightcut - refractedcut dtheta = dtheta[0:-2] results = results[:-1] miss = results[ -3] #take the last results, this is how many km away the ray is when dtheta is satisfied ploterrorvariation(dtheta[0:-2], results[0:-2], straightrayalt) iterationmax = iterationmax + 1
def cartesianbending(xyzpoints, initialangle, sv, MEX, TGO): #form a coordinate system where tgo is @ y=0 and x= (5000 +norm), Mar's Barrycenter being @ [5000,0] #initialise non-global variables miniray = np.zeros(10) raystep = np.zeros( (2, 10000)) # create a large array to populate and then shrink later barry2mex = np.linalg.norm(MEX) barry2tgo = np.linalg.norm(TGO) #find the martian geomoerty so you can reliably find the altitude of a point marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] _, _, MEXalt = spice.recgeo(MEX, equatorialradii, flatteningcoefficient) _, _, TGOalt = spice.recgeo(TGO, equatorialradii, flatteningcoefficient) #the possition of MEX is found by assuming that it will be somewhere over the relative horizon from TGO # (meaning over θ = 90°), finding the angle between the MEX and TGO's negative vector, will give the coords of MEX MexRelativeElevation = spice.vsep(-TGO, MEX) #radians mex_y = barry2mex * np.sin(MexRelativeElevation) mex_x = barry2mex * np.cos(MexRelativeElevation) mex = np.array([0 - mex_x, mex_y]) tgo = np.array([0 + barry2tgo, 0]) barry = np.array([0, 0]) #to plot the non-refracted propogation, we must convert the 3d xyzpoints to 2d, we do this the same way we found the x&y for MEX # ,using the norm distance and sep from -TGO5 length = np.size(xyzpoints, 1) UnrefractedDistance = np.linalg.norm(xyzpoints[:, 0] - xyzpoints[:, -1]) #in km UnrefractedRay = np.zeros([2, length]) for i in range(length): point = xyzpoints[:, i] + 0 #need to put vector into temp variable as spice cant handle strided array inputs angle = spice.vsep(-TGO, point) norm = np.linalg.norm(point) point_x = norm * np.cos(angle) point_y = norm * np.sin(angle) UnrefractedRay[0, i] = 0 - point_x UnrefractedRay[1, i] = point_y #psuedo #.decide what the unit is (probably iterable),start propergation with the initial angle in one unit direction (doesnt have to be 1 km), #. feed each unit/10 into an alt finder and calc the avg N for this unit #. simple snell to find new angle with n0/n1 (does it need entry angle?) #.find barry2ray possition, and the bend will be from the normal of that (simple) #.rotate current vector up(iono) or down(neutral) minutely #.save coords at each unit step # . propergate #.exit when y = ~0 (bare in mind the nuetral and really f**k up at low alts), this should show in a plot anyways #. check variance with an altered ploterrorvariation() function #.calc miss, x value will usually be greater than tgo(x) because it will mostly bend upwards initialtheta = -( spice.vsep(MEX - TGO, MEX) ) #this will produce and angle that is likly not going to be exactly on #the original propagation path, you compare to this if there is a drifting error, as both this and the resultant refracted ray # have the same bias error. THIS ANGLE IS BENDING ANTICLOCKWISE IN THIS FRAME (BENDING UPWARDS) nicetohave = np.degrees(initialtheta) unit = 1 # in km rotationvector = np.array(((np.cos(initialtheta), -np.sin(initialtheta)), (np.sin(initialtheta), np.cos(initialtheta)))) #get unit vecotr of -MEX (then add this vecotr to MEX for each alt calcultation) unitmex = -mex / barry2mex #unit direction (2d) direction = unitmex.dot( rotationvector ) * unit #make a 2d vector coming from MEX YOU DO NOT KNOW WHAT WAY THIS IS ROTATING stage = 0 t = 0 # index counter for steps along the ray while stage < 2: #==0first unit, so move two units. ==1 propergate step by step. ==2 exit and analyse entire path #take the alt at 10 possitions across this unit if stage == 0: for k in range(10): point = mex + (k * (direction / 10)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) miniray[k] = np.linalg.norm(point) - 3389 N0 = findrefractivity(miniray, 10) raystep[:, t] = point #save the last location t = t + 1 stage = stage + 1 if t == 5440: print('stophere') if stage == 1: for k in range(10): point = raystep[:, t - 1] + (k * (direction / 10)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) #THIS ONLY WORKS IN 3D # IMPLEMENTING MARS AS A SIMPLE CIRCLE OF AVERAGE 3389 KM RADIUS, !THIS WILL BE UPDATED TO ELLIPSE! miniray[k] = np.linalg.norm(point) - 3389 raystep[:, t] = point #9 is the end of the unit, and refraction always happens relative to the center of refractivity, so rotate off this vector N1 = findrefractivity(miniray, 10) if point[1] < 0: #if the position drops below the x axis stage = stage + 1 #increase the stage value so the while loop is exited #DEBUGGING CATCHES: r = N0 / N1 if r == 1: #only bend when there is a refractive gradient between consecutive air volumes t = t + 1 N0 = N1 continue #find the angle between the unit (air volume) boarder and the current direction unitrotationaxis = -(raystep[:, t] / np.linalg.norm(raystep[:, t])) #unitdirection = direction #MAYBE ALTERING UNITS WILL EFFECT THIS * OR / BY UNIT, CANT FIGURE OUT NOW, OK WHEN UNIT =1 DotProduct = np.dot(unitrotationaxis, direction) AngleofIncidence = (math.pi / 2) - np.arccos( DotProduct) #angle it enters the next air volume #simple snell law to find the bending angle (should be tiny angle) AngleofRefraction = np.arcsin(r * np.sin(AngleofIncidence)) # THIS IS NOT EXACTLY WHAT THE TURN IN DIRECTION IS, NEED TO THINK ABOUT rotateby = 300 * ((AngleofIncidence - AngleofRefraction) ) #+ve =clockwise, -ve=anticlockwise INCIDENCEDEGREES = np.degrees(AngleofIncidence) REFRACTIONDEGREES = np.degrees(AngleofRefraction) ROTATIONDEGREES = np.degrees(rotateby) #an if statement is required, if this if ROTATIONDEGREES > 1 or ROTATIONDEGREES < -1: print('stophere, u r bending to much') rotationvector = np.array( ((np.cos(rotateby), -np.sin(rotateby)), (np.sin(rotateby), np.cos(rotateby)))) direction = direction.dot(rotationvector) t = t + 1 N0 = N1 error = np.zeros(t) g = 0 #INSERT THE SOLUTION HERE: #method4 error = finderror(raystep, UnrefractedRay, initialtheta) #smoothraystep = interpolate.interp1d(raystep[0],raystep[1], kind = 'linear') #smoothUnrefractedRay = interpolate.interp1d(UnrefractedRay[0],UnrefractedRay[1], kind = 'linear') # i=0 # raysteparea = np.trapz(raystep[0:6482], axis =0) # unrefractedarea = np.trapz(UnrefractedRay[0:6482], axis =0) # #for i in range(6482): # error[i] = raysteppoint[0]-UnrefractedRaypoint[0] + 0.25 #x_progress = np.floor(range(int(np.floor(max(raystep[0,:])) - np.floor(min(raystep[0,:])))) + raystep[0,0]) # raystep_xy = np.zeros((2,np.size(x_progress))) #UnrefractedRay_xy = np.zeros((2,np.size(x_progress))) error = np.zeros(t) # smallerraystep_x = raystep[0,:] # smallerraystep_x = smallerraystep_x[smallerraystep_x != 0] # roundedraysteps_x = np.floor(smallerraystep_x) # roundedunrefracted_x = np.floor(UnrefractedRay[0,:]) # #rounded_x = np.floor(UnrefractedRay[0,:]) # #analyse at each raystep to see the error, you can do an x value match and then correct for the delay #for i in range(t): # raystep_x = raystep[0,:] # UnrefractedRay_x = UnrefractedRay[0,:] # idxray = np.searchsorted(UnrefractedRay_x , raystep_x[i], side ='left') # if idxray > UnrefractedRay_x[-1]: # break # UnrefractedRay_xy = UnrefractedRay[:,idxray] # #idxUnrefracted = np.searchsorted(roundedunrefracted_x, x_progress[i], side ='left') # and raystep_x[0,:] > x_progress[i] ]# to deal with the high precision numbers # if idxray ==[]: # break #ray_y = raystep[1,idxray] #unrefracted_y = UnrefractedRay[1,idxUnrefracted] #error[i] = ray_y-unrefracted_y # index_xUnrefracted= np.where(UnrefractedRay[0,:] < (x_progress[i] + 1) and UnrefractedRay[0,:] > x_progress[i] ) # it is not found because Ray has many decimal points # index_xRefracted = np.where(raystep[0,:] < (x_progress[i] +1) and raystep[0,:] > x_progress[i]) #maybe add a -+ limiter aound it? # indexU = index_xUnrefracted[1][0] # UnrefractedRaypoint = UnrefractedRay[:,indexU] # indexR = index_xRefracted[1][0] # raysteppoint = raystep[:,indexR] # error[i] = raysteppoint[0]-UnrefractedRaypoint[0] + 0.25 # # #PossiblePoints = PossiblePoints[PossiblePoints > x_progress[i] ]# splitting the conditional across two lines due to a ambiguity error # # #PossiblePoints1 = PossiblePoints[PossiblePoints !=0] # error = error[error !=0] # #LETS SMOOTH THE ERRORS TO FIX YOUR ROUNDING ERROR # window_size = 10 # i = 0 # moving_averages = [] # while i < len(error) - window_size + 1: # this_window = error[i : i + window_size] # window_average = sum(this_window) / window_size # moving_averages.append(window_average) # i += 1 # plt.plot( moving_averages , '.') # plt.ylabel('Error') # plt.xlabel('X progression') # plt.show() # # #F**K IT EVEN OLDER VERSION # # #FIND VALUE IN RAYSTEP THAT SUITS THE XPROGRESS CONDITIONS # # raystep_x = raystep[0,:] # # PossiblePoints = raystep_x[raystep_x < (x_progress[i]+1)]# and raystep_x[0,:] > x_progress[i] ]# to deal with the high precision numbers # # PossiblePoints = PossiblePoints[PossiblePoints > x_progress[i] ]# splitting the conditional across two lines due to a ambiguity error # # PossiblePoints1 = PossiblePoints[PossiblePoints !=0] # # if PossiblePoints.size ==0:#very rarely there maybe be no value for this value of x # # continue #we might have got to the end # # SearchFor = PossiblePoints1[0]# only take the first value # # index = np.where(raystep_x == SearchFor) # # Index1 = index[0][0] # # raystep_xy[:,i] = raystep[:,Index1] # # #FIND VALUE IN UNREFRACTED THAT SUITS THE XPROGRESS CONDITIONS # # UnrefractedRay_x = UnrefractedRay[0,:] # # PossiblePoints = UnrefractedRay_x[UnrefractedRay_x< (x_progress[i]+1)]# to deal with the high precision numbers # # PossiblePoints = PossiblePoints[PossiblePoints > x_progress[i] ]# splitting the conditional across two lines due to a ambiguity error # # PossiblePoints2 = PossiblePoints[PossiblePoints !=0] # # if PossiblePoints.size ==0: # # continue # # SearchFor = PossiblePoints2[0]# only take the first value # # index = np.where(UnrefractedRay_x == SearchFor) # # Index2 = index[0][0] # # UnrefractedRay_xy[:,i] = UnrefractedRay[:,Index2] # # # OLD METHOD # #error[i] = np.linalg.norm(raystep_xy[:,i]-UnrefractedRay_xy[:,i]) #probs alter the format of 'index' # g=g+1 #only do this if it set!! # #error = error[error < 0.1 ]#take every 10th value] # #x_progress = x_progress[0::10] # plt.plot( error , '.') # plt.ylabel('Error') # plt.xlabel('X progression') # plt.show() fig, ax = plt.subplots() plt.plot(barry[0], barry[1], 'x') plt.annotate('$\u2642$', (barry[0], barry[1]), fontsize=20) marsradii = plt.Circle((0, 0), 3389, color='red', fill=False) ax.add_artist(marsradii) plt.plot(mex[0], mex[1], '.') plt.annotate('MEX', (mex[0], mex[1])) plt.plot(tgo[0], tgo[1], 'o') plt.annotate('TGO', (tgo[0], tgo[1])) plt.plot(UnrefractedRay[0], UnrefractedRay[1], ':') plt.annotate( 'Distance = %ikm' % UnrefractedDistance, (UnrefractedRay[0, length // 2], UnrefractedRay[1, length // 2]), fontsize=8) plt.plot(raystep[0], raystep[1], '.') plt.gca().set_aspect('equal', adjustable='box') ax.set_xlabel('X') ax.set_ylabel('Y') plt.show() print('stophere')
def flatbending(xyzpoints, initialangle, sv, MEX, TGO): #form a coordinate system where tgo is @ y=0 and x= (5000 +norm), Mar's Barrycenter being @ [5000,0] subgroupsize = 10 #initialise non-global variables miniray = np.zeros(subgroupsize) raystep = np.zeros( (2, 100000000)) # create a large array to populate and then shrink later barry2mex = np.linalg.norm(MEX) barry2tgo = np.linalg.norm(TGO) #find the martian geomoerty so you can reliably find the altitude of a point marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] _, _, MEXalt = spice.recgeo(MEX, equatorialradii, flatteningcoefficient) _, _, TGOalt = spice.recgeo(TGO, equatorialradii, flatteningcoefficient) #the possition of MEX is found by assuming that it will be somewhere over the relative horizon from TGO # (meaning over θ = 90°), finding the angle between the MEX and TGO's negative vector, will give the coords of MEX MexRelativeElevation = spice.vsep(-TGO, MEX) #radians mex_y = barry2mex * np.sin(MexRelativeElevation) mex_x = barry2mex * np.cos(MexRelativeElevation) mex = np.array([0 - mex_x, mex_y]) tgo = np.array([0 + barry2tgo, 0]) barry = np.array([0, 0]) #to plot the non-refracted propogation, we must convert the 3d xyzpoints to 2d, we do this the same way we found the x&y for MEX # ,using the norm distance and sep from -TGO5 length = np.size(xyzpoints, 1) UnrefractedDistance = np.linalg.norm(xyzpoints[:, 0] - xyzpoints[:, -1]) #in km UnrefractedRay = np.zeros([2, length]) for i in range(length): #conversion to 2D point = xyzpoints[:, i] + 0 #need to put vector into temp variable as spice cant handle strided array inputs angle = spice.vsep(-TGO, point) norm = np.linalg.norm(point) point_x = norm * np.cos(angle) point_y = norm * np.sin(angle) UnrefractedRay[0, i] = 0 - point_x UnrefractedRay[1, i] = point_y #this will produce and angle that is likly not going to be exactly on #the original propagation path, you compare to this if there is a drifting error, as both this and the resultant refracted ray # have the same bias error. THIS ANGLE IS BENDING ANTICLOCKWISE IN THIS FRAME (BENDING UPWARDS) initialtheta = -(spice.vsep(MEX - TGO, MEX)) nicetohave = np.degrees(initialtheta) unit = 1 # in km rotationvector = np.array(((np.cos(initialtheta), -np.sin(initialtheta)), (np.sin(initialtheta), np.cos(initialtheta)))) #get unit vecotr of -MEX (then add this vecotr to MEX for each alt calcultation) unitmex = -mex / barry2mex #unit direction (2d) initialdirection = unitmex.dot( rotationvector ) * unit #make a 2d vector coming from MEX YOU DO NOT KNOW WHAT WAY THIS IS ROTATING iterationcount = 0 #while iterationcount<100: #print( "Finding Bending Angle (", str(iterationcount) ,"% Complete)") errorstore = np.zeros((11, 100000)) Nstore = np.zeros(20000) while iterationcount < 100: tic = timer.perf_counter() if iterationcount == 0: direction = initialdirection else: # the initail direction must be rotated by a 10th of the miss at the end missangle = missangle / 1 missrotationvector = np.array( ((mp.cos(missangle), mp.sin(missangle)), (mp.sin(missangle), mp.cos(missangle)))) direction = initialdirection.dot(missrotationvector) initialdirection = direction turningcounter = 0 progress = [0, 0] stage = 0 t = 0 with tqdm(total=mex[1], desc="Progress", leave=False) as pbar: while stage < 2: #==0first unit, so move two units. ==1 propergate step by step. ==2 exit and analyse entire path #take the alt at 10 possitions across this unit #lets get a quick calculated for the magnitude of the direction MAAAAG = np.linalg.norm(direction) # this should = unit if stage == 0: for k in range(subgroupsize): #this starts with 0 point = mex + ((k + 1) * (direction / subgroupsize)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) miniray[k] = np.linalg.norm( point) - 3389 #average radii of mars N0 = findrefractivity(miniray, subgroupsize) raystep[:, t] = point #save the last location t = t + 1 stage = stage + 1 if stage == 1: for k in range(subgroupsize): point = raystep[:, t - 1] + ( (k + 1) * (direction / subgroupsize) ) #am i double counting the end of the last and the start of the next? #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) #THIS ONLY WORKS IN 3D # IMPLEMENTING MARS AS A SIMPLE CIRCLE OF AVERAGE 3389 KM RADIUS, !THIS WILL BE UPDATED TO ELLIPSE! miniray[k] = np.linalg.norm(point) - 3389 raystep[:, t] = point #9 is the end of the unit, and refraction always happens relative to the center of refractivity, so rotate off this vector N1 = findrefractivity(miniray, subgroupsize) if point[1] < 0: #if the position drops below the x axis stage = stage + 1 #increase the stage value so the while loop is exited #this section allows for better timing of the function, increment the progresbar by 1 if the current #position goes one y-value lower currenty = raystep[1, t] progress[1] = mex[ 1] - currenty #this value will be increasing from 0 -> Mex height increment = np.floor(progress[1]) - np.floor( progress[0]) #only when if increment == 1: pbar.update(1) progress[0] = progress[1] if abs(N0) < 1e-20: #catch for precision errors Nstore[t] = N1 t = t + 1 N0 = N1 continue #print('Current Y possition is', currenty) #this is alt, so is ~3389 km smaller than the vector r = N0 / N1 #NEED MORE PRECISION numorator = mpf(N0) + mpf(1) denominator = mpf(N1) + mpf(1) rbending = mp.fdiv( numorator, denominator) #average would just add 1 to total N if t == 5000: #only bend when there is a refractive gradient between consecutive air volumes[NO CHANGE IN DIRECTION] t = t + 1 N0 = N1 continue #this section is only reached if a turning is going to happen # ,testing to see if there is 10 X less turing if the units are 10X smaller -TRUE TEST = float(rbending) if TEST != 1: turningcounter = turningcounter + 1 # !! NOW WITH PRECISION !! #find the angle between the unit (air volume) boarder and the current direction unitrotationaxis = raystep[:, t] / np.linalg.norm( raystep[:, t]) #unitdirection = direction #MAYBE ALTERING UNITS WILL EFFECT THIS * OR / BY UNIT, CANT FIGURE OUT NOW, OK WHEN UNIT =1 DotProduct = np.dot(unitrotationaxis, direction) AngleofIncidence = (math.pi / 2) - mp.acos( DotProduct) #angle it enters the next air volume #simple snell law to find the bending angle (should be tiny angle) AngleofRefraction = mp.asin(rbending * mp.sin(AngleofIncidence)) # THIS IS NOT EXACTLY WHAT THE TURN IN DIRECTION IS, NEED TO THINK ABOUT rotateby = ((AngleofIncidence - AngleofRefraction) ) #+ve =clockwise, -ve=anticlockwise INCIDENCEDEGREES = mp.degrees(AngleofIncidence) REFRACTIONDEGREES = mp.degrees(AngleofRefraction) ROTATIONDEGREES = mp.degrees(rotateby) #an if statement is required, if this if ROTATIONDEGREES > 1 or ROTATIONDEGREES < -1: print('stophere, u r bending to much') rotationvector = np.array( ((mp.cos(rotateby), -mp.sin(rotateby)), (mp.sin(rotateby), mp.cos(rotateby)))) direction = direction.dot(rotationvector) N0 = N1 #store N1 to calc electric distance Nstore[t] = N1 t = t + 1 #pbar.refresh() error = np.zeros(t) #print("Number of turns:", turningcounter) error = finderror(raystep, UnrefractedRay) miss = error missangle = mp.asin(miss / UnrefractedDistance) toc = timer.perf_counter() passingtime = toc - tic print(' miss =', format(miss * 1000, '.5f'), 'm || Angle =', nstr(mp.degrees(missangle), 5), '° || Speed =', passingtime, ' Sec \n', sep=" ", end=" ", flush=True) if abs(miss) < 1e-5: #is the miss smaller than 10 cm? #ploterrortraces(errorstore,t) break iterationcount = iterationcount + 1 #find the total bending angle at MEX for this final configuration unit_initial = initialdirection / np.linalg.norm(initialdirection) dot_product = np.dot(unit_initial, unitmex) FinalBendingAngle = mp.acos(dot_product) #from the refractive profile from MEX ->TGO, calc the intergral of the change in wavelength to aquire doppler Nstore = Nstore[Nstore != 0] Nstore = Nstore + 1 #convert N deltas into values of N ElectricDistance = np.sum( Nstore ) #N * wavelengths in a km (UNITS MUST BE KEPT THE SAME AS STEP-SIZE) return FinalBendingAngle, ElectricDistance
def flatbending(xyzpoints, initialangle, sv, MEX, TGO): #form a coordinate system where tgo is @ y=0 and x= (5000 +norm), Mar's Barrycenter being @ [5000,0] #initialise non-global variables miniray = np.zeros(10) raystep = np.zeros( (2, 100000000)) # create a large array to populate and then shrink later barry2mex = np.linalg.norm(MEX) barry2tgo = np.linalg.norm(TGO) #find the martian geomoerty so you can reliably find the altitude of a point marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] _, _, MEXalt = spice.recgeo(MEX, equatorialradii, flatteningcoefficient) _, _, TGOalt = spice.recgeo(TGO, equatorialradii, flatteningcoefficient) #the possition of MEX is found by assuming that it will be somewhere over the relative horizon from TGO # (meaning over θ = 90°), finding the angle between the MEX and TGO's negative vector, will give the coords of MEX MexRelativeElevation = spice.vsep(-TGO, MEX) #radians mex_y = barry2mex * np.sin(MexRelativeElevation) mex_x = barry2mex * np.cos(MexRelativeElevation) mex = np.array([0 - mex_x, mex_y]) tgo = np.array([0 + barry2tgo, 0]) barry = np.array([0, 0]) #to plot the non-refracted propogation, we must convert the 3d xyzpoints to 2d, we do this the same way we found the x&y for MEX # ,using the norm distance and sep from -TGO5 length = np.size(xyzpoints, 1) UnrefractedDistance = np.linalg.norm(xyzpoints[:, 0] - xyzpoints[:, -1]) #in km UnrefractedRay = np.zeros([2, length]) for i in range(length): point = xyzpoints[:, i] + 0 #need to put vector into temp variable as spice cant handle strided array inputs angle = spice.vsep(-TGO, point) norm = np.linalg.norm(point) point_x = norm * np.cos(angle) point_y = norm * np.sin(angle) UnrefractedRay[0, i] = 0 - point_x UnrefractedRay[1, i] = point_y #this will produce and angle that is likly not going to be exactly on #the original propagation path, you compare to this if there is a drifting error, as both this and the resultant refracted ray # have the same bias error. THIS ANGLE IS BENDING ANTICLOCKWISE IN THIS FRAME (BENDING UPWARDS) initialtheta = -(spice.vsep(MEX - TGO, MEX)) nicetohave = np.degrees(initialtheta) unit = 1 # in km rotationvector = np.array(((np.cos(initialtheta), -np.sin(initialtheta)), (np.sin(initialtheta), np.cos(initialtheta)))) #get unit vecotr of -MEX (then add this vecotr to MEX for each alt calcultation) unitmex = -mex / barry2mex #unit direction (2d) direction = unitmex.dot( rotationvector ) * unit #make a 2d vector coming from MEX YOU DO NOT KNOW WHAT WAY THIS IS ROTATING iterationcount = 0 #while iterationcount<100: print("Finding Bending Angle (", str(iterationcount), "% Complete)") #some function based on miss (miss begins with ) stage = 0 t = 0 # index counter for steps along the ray while stage < 2: #==0first unit, so move two units. ==1 propergate step by step. ==2 exit and analyse entire path #take the alt at 10 possitions across this unit if stage == 0: for k in range(10): point = mex + (k * (direction / 10)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) miniray[k] = np.linalg.norm( point) - 3389 #average radii of mars N0 = findrefractivity(miniray, 10) raystep[:, t] = point #save the last location t = t + 1 stage = stage + 1 if stage == 1: for k in range(10): point = raystep[:, t - 1] + (k * (direction / 10)) #_,_,miniray[k] = spice.recgeo(point, equatorialradii,flatteningcoefficient) #THIS ONLY WORKS IN 3D # IMPLEMENTING MARS AS A SIMPLE CIRCLE OF AVERAGE 3389 KM RADIUS, !THIS WILL BE UPDATED TO ELLIPSE! miniray[k] = np.linalg.norm(point) - 3389 raystep[:, t] = point #9 is the end of the unit, and refraction always happens relative to the center of refractivity, so rotate off this vector N1 = findrefractivity(miniray, 10) if point[1] < 0: #if the position drops below the x axis stage = stage + 1 #increase the stage value so the while loop is exited # if N0 !=1: # print('querycode') currenty = raystep[1, t] print('Current Y possition is', currenty) r = N0 / N1 #NEED MORE PRECISION if r == 1: #only bend when there is a refractive gradient between consecutive air volumes[NO CHANGE IN DIRECTION] t = t + 1 N0 = N1 continue #find the angle between the unit (air volume) boarder and the current direction unitrotationaxis = -(raystep[:, t] / np.linalg.norm(raystep[:, t])) #unitdirection = direction #MAYBE ALTERING UNITS WILL EFFECT THIS * OR / BY UNIT, CANT FIGURE OUT NOW, OK WHEN UNIT =1 DotProduct = np.dot(unitrotationaxis, direction) AngleofIncidence = (math.pi / 2) - np.arccos( DotProduct) #angle it enters the next air volume #simple snell law to find the bending angle (should be tiny angle) AngleofRefraction = np.arcsin(r * np.sin(AngleofIncidence)) # THIS IS NOT EXACTLY WHAT THE TURN IN DIRECTION IS, NEED TO THINK ABOUT rotateby = 300 * ((AngleofIncidence - AngleofRefraction) ) #+ve =clockwise, -ve=anticlockwise INCIDENCEDEGREES = np.degrees(AngleofIncidence) REFRACTIONDEGREES = np.degrees(AngleofRefraction) ROTATIONDEGREES = np.degrees(rotateby) #an if statement is required, if this if ROTATIONDEGREES > 1 or ROTATIONDEGREES < -1: print('stophere, u r bending to much') rotationvector = np.array( ((np.cos(rotateby), -np.sin(rotateby)), (np.sin(rotateby), np.cos(rotateby)))) direction = direction.dot(rotationvector) #if np.linalg.norm(direction)< 0.08:# assuming unit is set to 0.1 # print(' your movement direction is shrinking') t = t + 1 N0 = N1 error = np.zeros(t) g = 0 #error = finderror(raystep, UnrefractedRay, initialtheta) miss = error[-1] # +ve miss needs a clockwise rotation, iterationcount = iterationcount + 1 fig, ax = plt.subplots() plt.plot(barry[0], barry[1], 'x') plt.annotate('$\u2642$', (barry[0], barry[1]), fontsize=20) marsradii = plt.Circle((0, 0), 3389, color='red', fill=False) ax.add_artist(marsradii) plt.plot(mex[0], mex[1], '.') plt.annotate('MEX', (mex[0], mex[1])) plt.plot(tgo[0], tgo[1], 'o') plt.annotate('TGO', (tgo[0], tgo[1])) plt.plot(UnrefractedRay[0], UnrefractedRay[1], ':') plt.annotate( 'Distance = %ikm' % UnrefractedDistance, (UnrefractedRay[0, length // 2], UnrefractedRay[1, length // 2]), fontsize=8) plt.plot(raystep[0], raystep[1], ':') plt.gca().set_aspect('equal', adjustable='box') ax.set_xlabel('X') ax.set_ylabel('Y') plt.show() print('stophere')
kwargs = {'from_ref': from_ref, 'to_ref': to_ref} tais = utc2tai(utc, utc_end, deltat) return distribute_work(xform_spice, xfunc, tais, **kwargs) def utc2scs(utc, utc_end, deltat, sc): tais = utc2tai(utc, utc_end, deltat) return utc2scs_spice(tais, sc) def scs2utc(scs, sc, deltat): return scs2utc_spice(scs, sc, deltat) _POSITION_KIND = { None : lambda x: x, 'rectangular': lambda x: x, 'latitudinal': sp.reclat, 'radec' : sp.recrad, 'spherical' : sp.recsph, 'cylindrical': sp.reccyl, 'geodetic' : lambda x: sp.recgeo(x, 6378.14, 0.0033536422844278) } _TRANSFORM_KIND = { None : lambda x: x, 'matrix' : lambda x: x, 'angle' : lambda x: sp.m2eul(x, 3, 2, 1), 'quaternion' : sp.m2q }
def flatbending(xyzpoints, initialangle, MEX, TGO): # form a coordinate system where tgo is @ y=0 and x= (5000 +norm), Mar's Barrycenter being @ [5000,0] class SpiceVariables: obs = '-41' # NAIF code for MEX # NAIF code for TGO ['EARTH'/'SUN'/ a groundstation etc] target = '-143' obsfrm = 'IAU_MARS' abcorr = 'NONE' crdsys = 'LATITUDINAL' coord = 'LATITUDE' stepsz = 100.0 # Check every 300 seconds if there is an occultation MAXILV = 100000 # Max number of occultations that can be returned by gfoclt bshape = 'POINT' fshape = 'DSK/UNPRIORITIZED' front = 'MARS' fframe = 'IAU_MARS' TFMT = 'YYYY-MM-DD HR:MN:SC' # Format that Cosmographia understands sv = SpiceVariables() subgroupsize = 1 unit = 0.1 # in km mp.dps = 40 # initialise non-global variables miniray = np.zeros(subgroupsize) # create a large array to populate and then shrink later raystep = np.zeros((2, 100000000)) barry2mex = np.linalg.norm(MEX) barry2tgo = np.linalg.norm(TGO) # find the martian geomoerty so you can reliably find the altitude of a point marsrad = spice.bodvrd(sv.front, 'RADII', 3) flatteningcoefficient = (marsrad[1][0] - marsrad[1][2]) / marsrad[1][0] equatorialradii = marsrad[1][0] TGO = TGO + 0 MEX = MEX + 0 # force to be non-strided _, _, MEXalt = spice.recgeo(MEX, equatorialradii, flatteningcoefficient) _, _, TGOalt = spice.recgeo(TGO, equatorialradii, flatteningcoefficient) # the possition of MEX is found by assuming that it will be somewhere over the relative horizon from TGO # (meaning over θ = 90°), finding the angle between the MEX and TGO's negative vector, will give the coords of MEX MexRelativeElevation = spice.vsep(-TGO, MEX) # radians mex_y = barry2mex * np.sin(MexRelativeElevation) mex_x = barry2mex * np.cos(MexRelativeElevation) mex = np.array([0 - mex_x, mex_y]) tgo = np.array([0 + barry2tgo, 0]) barry = np.array([0, 0]) # to plot the non-refracted propogation, we must convert the 3d xyzpoints to 2d, we do this the same way we found the x&y for MEX # ,using the norm distance and sep from -TGO5 length = np.size(xyzpoints, 1) UnrefractedDistance = np.linalg.norm(xyzpoints[:, 0] - xyzpoints[:, -1]) # in km UnrefractedRay = np.zeros((2, length)) for i in range(length): # need to put vector into temp variable as spice cant handle strided array inputs point = xyzpoints[:, i] + 0 angle = spice.vsep(-TGO, point) norm = np.linalg.norm(point) point_x = norm * np.cos(angle) point_y = norm * np.sin(angle) UnrefractedRay[0, i] = 0 - point_x UnrefractedRay[1, i] = point_y # this will produce and angle that is likly not going to be exactly on # the original propagation path, you compare to this if there is a drifting error, as both this and the resultant refracted ray # have the same bias error. THIS ANGLE IS BENDING ANTICLOCKWISE IN THIS FRAME (BENDING UPWARDS) initialtheta = -(spice.vsep(MEX - TGO, MEX)) nicetohave = np.degrees(initialtheta) rotationvector = np.array(((np.cos(initialtheta), -np.sin(initialtheta)), (np.sin(initialtheta), np.cos(initialtheta)))) # get unit vecotr of -MEX (then add this vecotr to MEX for each alt calcultation) unitmex = -mex / barry2mex # unit direction (2d) # make a 2d vector coming from MEX YOU DO NOT KNOW WHAT WAY THIS IS ROTATING initialdirection = unitmex.dot(rotationvector) * unit iterationcount = 0 # while iterationcount<100: #print( "Finding Bending Angle (", str(iterationcount) ,"% Complete)") errorstore = np.zeros((11, 5000000)) miss = inf missangle = inf while iterationcount < 100: if iterationcount == 0: direction = initialdirection else: # the initail direction must be rotated by a 10th of the miss at the end missangle = missangle / 1 missrotationvector = np.array( ((mp.cos(missangle), -mp.sin(missangle)), (mp.sin(missangle), mp.cos(missangle)))) direction = initialdirection.dot(missrotationvector) # to make the produced direction reach mpmath dp level # a= mp.cos(missangle) ; b = -mp.sin(missangle) #ORIGINAL DID NOT GAVE THIS NEG, SO IT HAS BEEN MADE POSITIVE # c = mp.sin(missangle) ; d = mp.cos(missangle) # rotationvector = np.array([[a,b],[c,d]]) # direction = direction.dot(rotationvector) initialdirection = direction Nstore = np.zeros(20000000) turningcounter = 0 progress = [0, 0] stage = 0 t = 0 tic = timer.perf_counter() # raypositions = pd.DataFrame(raystep.T, columns=['x', 'y'])# should produce an empty dataframe to store # the high precision positions with tqdm(total=mex[1], desc="Progress", leave=False) as pbar: while stage < 2: # ==0first unit, so move two units. ==1 propergate step by step. ==2 exit and analyse entire path # take the alt at 10 possitions across this unit # lets get a quick calculated for the magnitude of the direction MAAAAG = np.linalg.norm(direction) # this should = unit if stage == 0: for k in range(subgroupsize): # this starts with 0 point = mex + ((k + 1) * (direction / subgroupsize)) miniray[k] = np.linalg.norm( point) - 3389 # average radii of mars N0 = findrefractivity(miniray, subgroupsize) raystep[0, t] = point[0] raystep[1, t] = point[1] # save the last location t = t + 1 stage = stage + 1 if stage == 1: for k in range(subgroupsize): subvalue = ((k + 1) * (direction / subgroupsize)) # am i double counting the end of the last and the start of the next? point = raystep[:, t - 1] + subvalue # IMPLEMENTING MARS AS A SIMPLE CIRCLE OF AVERAGE 3389 KM RADIUS, !THIS WILL BE UPDATED TO ELLIPSE! # provides the alt, this can have less precision miniray[k] = np.linalg.norm(point) - 3389 raystep[0, t] = point[0] # x raystep[1, t] = point[1] # y N1 = findrefractivity(miniray, subgroupsize) if point[1] < 0: # if the position drops below the x axis stage = stage + 1 # increase the stage value so the while loop is exited currenty = raystep[1, t] # this value will be increasing from 0 -> Mex height progress[1] = mex[1] - currenty increment = np.floor(progress[1]) - np.floor( progress[0]) # only when if increment == 1: pbar.update(1) progress[0] = progress[1] # catch for precision errors e-50 is basically the entire propagation if abs(N0) < 1e-10: Nstore[t] = N1 t = t + 1 N0 = N1 continue # ensure all the turns are being implemented # print('Current Y possition is', currenty) #this is alt, so is ~3389 km smaller than the vector numorator = mpf(N0) + mpf(1) denominator = mpf(N1) + mpf(1) # average would just add 1 to total N rbending = mp.fdiv(numorator, denominator) # only bend when there is a refractive gradient between consecutive air volumes[NO CHANGE IN DIRECTION] if t == 5000: t = t + 1 N0 = N1 continue # this section is only reached if a turning is going to happen # ,testing to see if there is 10 X less turing if the units are 10X smaller -TRUE # TEST = float(rbending) # if TEST != 1: # turningcounter = turningcounter+1 # !! NOW WITH PRECISION !! #ray = raypositions.iloc[t,:].values # find the angle between the unit (air volume) boarder and the current direction unitrotationaxis = raystep[:, t] / \ (np.linalg.norm(raystep[:, t])*unit) # unitdirection = direction #MAYBE ALTERING UNITS WILL EFFECT THIS * OR / BY UNIT, CANT FIGURE OUT NOW, OK WHEN UNIT =1 DotProduct = fdot(unitrotationaxis, direction) # angle it enters the next air volume AngleofIncidence = (math.pi / 2) - mp.acos(DotProduct) # simple snell law to find the bending angle (should be tiny angle) AngleofRefraction = mp.asin(rbending * mp.sin(AngleofIncidence)) # THIS IS NOT EXACTLY WHAT THE TURN IN DIRECTION IS, NEED TO THINK ABOUT # +ve =clockwise, -ve=anticlockwise rotateby = ((AngleofIncidence - AngleofRefraction)) INCIDENCEDEGREES = mp.degrees(AngleofIncidence) REFRACTIONDEGREES = mp.degrees(AngleofRefraction) ROTATIONDEGREES = mp.degrees(rotateby) predirection = direction # an if statement is required, if this if ROTATIONDEGREES > 1 or ROTATIONDEGREES < -1: print('stophere, u r bending to much') a = mp.cos(rotateby) b = -mp.sin(rotateby) c = mp.sin(rotateby) d = mp.cos(rotateby) rotationvector = np.array([[a, b], [c, d]]) direction = direction.dot(rotationvector) # rotationvector = matrix([[ mp.cos(rotateby), -mp.sin(rotateby)], # [mp.sin(rotateby), mp.cos(rotateby)]]) # direction = fdot(direction,rotationvector) if direction[1] != predirection[1]: # no bending has occured due to precision error # if the last direction is different to the current one then a turning has occured. # do we move forward with the same precision turningcounter = turningcounter + 1 N0 = N1 # store N1 to calc electric distance Nstore[t] = N1 t = t + 1 unit_initial = initialdirection / np.linalg.norm(initialdirection) dot_product = np.dot(unit_initial, unitmex) FinalBendingAngle = mp.acos(dot_product) # from the refractive profile from MEX ->TGO, calc the intergral of the change in wavelength to aquire doppler Nstore = Nstore[Nstore != 0] Nstore = 1 - Nstore # convert N deltas into values of N error = np.zeros(t) #print("Number of turns:", turningcounter) error = finderror(raystep, UnrefractedRay, initialtheta, iterationcount) miss = error[-1] # +ve miss needs a clockwise rotation errorstore[iterationcount, :t - 1] = error missangle = mp.asin(miss / UnrefractedDistance) toc = timer.perf_counter() passingtime = toc - tic print(' miss =', format(miss * 1000, '.5f'), 'm || Angle =', nstr(mp.degrees(FinalBendingAngle + initialtheta), 5), '° || Speed =', passingtime, ' Sec \n', sep=" ", end=" ", flush=True) #print('ANGLE miss =', mp.degrees(missangle) ,'Degrees') if abs(miss) < 1e-5: # is the miss smaller than 10 cm? # ploterrortraces(errorstore,t) print("stophere") break iterationcount = iterationcount + 1 # Expensive plotting (7sec) fig, ax = plt.subplots() plt.plot(barry[0], barry[1], 'x') plt.annotate('$\u2642$', (barry[0], barry[1]), fontsize=20) marsradii = plt.Circle((0, 0), 3389, color='red', fill=False) ionoradii = plt.Circle((0, 0), 3389 + 130, color='blue', fill=False) ax.add_artist(marsradii) ax.add_artist(ionoradii) plt.plot(mex[0], mex[1], '.') plt.annotate('MRO', (mex[0], mex[1])) plt.plot(tgo[0], tgo[1], 'o') plt.annotate('MO', (tgo[0], tgo[1])) plt.plot(UnrefractedRay[0], UnrefractedRay[1], ':') plt.annotate( 'Distance = %ikm' % UnrefractedDistance, (UnrefractedRay[0, length // 2], UnrefractedRay[1, length // 2]), fontsize=8) plt.plot(raystep[0], raystep[1], ':') plt.gca().set_aspect('equal', adjustable='box') ax.set_xlabel('X') ax.set_ylabel('Y') plt.plot(raystep[0, 0::500], raystep[1, 0::500], 'x', markersize=12) plt.show() # N * wavelengths in a km (UNITS MUST BE KEPT THE SAME AS STEP-SIZE) ElectricDistance = np.sum(Nstore) return FinalBendingAngle, ElectricDistance print('stophere')