def point_towards_sun(self, pixel_res=0.5): """ Compute the solar azimuth. Pixel resolution is required to stay within one pixel of the origin point """ # Check if surface point spoint was set if not self.spoint_set: raise SPointNotSetError # Get the difference vector poB=subsolar-origin with its tail at origin # and its head at the subsolar point poB = spice.vsub(self.subsolar, self.spoint) # get pixel scale in km/pixel and then divide by 2 to insure to stay # within a pixel of the origin point scale = (pixel_res / 1000.0) / 2.0 # the difference vector cuts through the body, # we need the tangent vector # to the surface at the origin point. vperp receives the perpendicular # component of the poB towards the spoint vector hpoB = spice.vperp(poB, self.spoint) # unitize the tangent vector and then scale it to within a pixel of the # origin point upoB = spice.vhat(hpoB) spoB = spice.vscl(scale, upoB) # Compute the new point in body fixed. This point will be within a # pixel of the origin but in the same direction as the requested la/lon # of the point of interest, i.e. the subsolar point nB = spice.vadd(self.spoint, spoB) coords = Coords.fromtuple(spice.reclat(nB)) return coords.dlon, coords.dlat
def point_towards_sun(self, pixel_res=0.5): """ Compute the solar azimuth. Pixel resolution is required to stay within one pixel of the origin point """ # Check if surface point spoint was set if not self.spoint_set: raise SPointNotSetError # Get the difference vector poB=subsolar-origin with its tail at origin # and its head at the subsolar point poB = spice.vsub(self.subsolar, self.spoint) # get pixel scale in km/pixel and then divide by 2 to insure to stay # within a pixel of the origin point scale = (pixel_res / 1000.0) / 2.0 # the difference vector cuts through the body, # we need the tangent vector # to the surface at the origin point. vperp receives the perpendicular # component of the poB towards the spoint vector hpoB = spice.vperp(poB, self.spoint) # unitize the tangent vector and then scale it to within a pixel of the # origin point upoB = spice.vhat(hpoB) spoB = spice.vscl(scale, upoB) # Compute the new point in body fixed. This point will be within a # pixel of the origin but in the same direction as the requested la/lon # of the point of interest, i.e. the subsolar point nB = spice.vadd(self.spoint, spoB) coords = SurfaceCoords.fromtuple(spice.reclat(nB)) return coords.dlon, coords.dlat
def dooneRandom(): ### Random normal unit vector unitNormal = sp.vhat([r.uniform(-1, 1) for i in xrange(3)]) ### Random positive semi-axes' lengths semi_axes = [abs(r.uniform(.5, 100)) for i in xrange(3)] ### Solve for surface point with that surface normal xyz = norm2surfpt(semi_axes, unitNormal) ### Use spiceypy.surfnm() to calculate surface unit normal vector, at ### solved-for surface point vector xyz, to compare to input unit normal ### vector, and calculate error magnitude, errMag surfnm = sp.surfnm(semi_axes[0], semi_axes[1], semi_axes[2], xyz) errVec = sp.vsub(surfnm, unitNormal) errMag = sp.vnorm(errVec) if doLog: pprint.pprint(dict(errVec=errVec, errMag=errMag)) ###return error magnitude return errMag
mars2tgo)[3] * sp.dpr() for time, mars2tgo in zip(list(times), list(mars2tgo_pos)) ]) print("Calculating altitudes") #calculate tangent point altitude altitudes = np.asfarray([ sp.npedln(mars_axes[0], mars_axes[1], mars_axes[2], line_point, line_vector)[1] for line_point, line_vector in zip( list(line_points), list(line_vectors)) ]) print("Checking if occultations real or not") #check that tgo is really behind mars as seen from sun: calculate angle between tgo-sun vector and tgo-mars centre vector sep_angles = np.asfarray([ sp.vsep(sp.vsub(line_coord, line_point), line_vector) for line_coord, line_point, line_vector in zip( list(tangent_coords), list(line_points), list(line_vectors)) ]) #if angle greater than 90 then tgo is between mars and sun, not behind mars valid_occ_indices = np.asfarray([ 1 if sep_angle <= sp.halfpi() else 0 for sep_angle in list(sep_angles) ]) print("Removing invalid points") #calculate all valid tangent altitudes tangent_altitudes = np.asfarray([ altitude if valid_occ == 1 else np.nan for altitude, valid_occ in zip(list(altitudes), list(valid_occ_indices))
"earth")[0] ### Use SPICE to calculate vector from earth to the the SSB-relative ### fixed star position with LT+S correction earth2star_lts = sp.spkcpt(vstar, ssb, j2000, et, j2000, "observer", LTS, "earth")[0] if do_debug: ### Ensure that light-time correction is zero for earth->star vector ### for star at fixed positon relative to SSB earth2star_lt = sp.spkcpt(vstar, ssb, j2000, et, j2000, "observer", LT, "earth")[0] assert 0.0 == sp.vnormg(sp.vsubg(earth2star_none, earth2star_lt, 6), 6) ### Calculate differences between gaiif_util.py and SPICE results ... ab_vec_spice = sp.vsub(earth2star_lts[:3], earth2star_none[:3]) ab_vec_gaia = sp.vscl(range2star, sp.vsub(uvstar_ab, uvstar_noab)) ab_vec_diff = sp.vsub(ab_vec_spice, ab_vec_gaia) ab_diff_frac = sp.vnorm(ab_vec_diff) / sp.vnorm(ab_vec_spice) no_ab_diff = sp.vsep(uvstar_noab, sp.vhat(earth2star_none[:3])) ab_diff = sp.vsep(uvstar_ab, sp.vhat(earth2star_lts[:3])) ab_diff_frac = sp.vsep(uvstar_ab, sp.vhat(earth2star_lts[:3])) try: ### ... Success assert 1e-15 > no_ab_diff assert 1e-8 > ab_diff except: ### ... Failure print(
degPerHour = 2.0 * dpr * twopi / hpd xTolerance = lambda xDiff: xDiff < 1e-10 xDiffTolerance = lambda x, xExpect: xTolerance(abs(x - xExpect)) et, iPass = et0, 0 while et < (et0 + spd + 1): ### Get the state of the MINUTE and HOUR bodies every half hour stMinute, lt = sp.spkezr(sMinute, et, 'J2000', 'NONE', sClock) stHour, lt = sp.spkezr(sHour, et, 'J2000', 'NONE', sClock) if (iPass % 2): ### On the half hour, the minute hand will be at RA=180, along [-1,0,0] assert xTolerance( sp.vnorm(sp.vsub([-1.0, 0., 0.], sp.vhat(stMinute[:3])))) else: ### On the hour, the minute hand will be at RA=0, at [+1,0,0] assert xTolerance( sp.vnorm(sp.vsub([1.0, 0., 0.], sp.vhat(stMinute[:3])))) vsepDeg = dpr * sp.vsep(stHour[:3], stMinute[:3]) vsepExpectDeg = (degPerHour * (iPass >> 1)) % 360 ### On the hour, the houre hand will be (30 * iPass) degrees clockwise ### from +X, and therefor also the same from the minute hand assert xDiffTolerance(vsepDeg, vsepExpectDeg) or xDiffTolerance( (360 - vsepDeg), vsepExpectDeg) ### Step to next half hour and pass et += halfHour iPass += 1
def star_in_fov(self ,vstar ,parallax_maspau=None ,pmra_maspy=None ,pmdec_maspy=None ): """Return True if the star (RA,Dec or xyz) argument is in the FOV Argument vstar is either an RA,Dec pair (degrees) or a 3-vector """ if self.fovtype == FOV.RADECBOXTYPE: ################################################################## ### Compare star vector to [RA,Dec] box ra,dec = parse_inertial(vstar,return_radec=True)[:2] for ralo,rahi,declo,dechi in self.radec_boxes: if ra<ralo: continue if ra>rahi: continue if dec<declo: continue if dec>dechi: continue return True,sp.radrec(1.,rpd*ra,rpd*dec) return False,None ### Get inertial star unit vector without RA,Dec uvinertial = uvraw = parse_inertial(vstar,return_radec=False) ### Corrections for direction to star ### - Assume all corrections are small and can be applied in units ### of radians to a unit vector in a plane perpendicular to the ### vector to the star ### - Proper Motion (PM) ### - Uses PM in RA and Dec only, not radial velocity and parallax if (not (None is self.obs_year) ) and (not (None in (pmra_maspy,pmdec_maspy,)) ) and (pmra_maspy != 0.0 or pmdec_maspy != 0.0): ### - Unit vectors E and N in plane perpendicular to star vector uveast = sp.ucrss([0,0,1],uvraw) uvnorth = sp.ucrss(uvraw,uveast) ### - Scale unit vectors in radians, and add to nominal vector ### - pmra_maspy from Gaia includes factor of secant(Declination) uvinertial = sp.vhat(sp.vlcom3(self.obs_year*rpmas*pmdec_maspy,uvnorth ,self.obs_year*rpmas*pmra_maspy,uveast ,1.0,uvinertial ) ) ### - Parallax if (not (None is self.obs_pos) ) and (not (None is parallax_maspau) ) and (parallax_maspau != 0.0): ### - Scale observer position, by parallax in mas/AU, then scale ### to radians (since star vector is unit vector), make that the ### new origin of the vector uvinertial = sp.vhat(sp.vsub(uvinertial ,sp.vscl(aupkm*parallax_maspau*rpmas,self.obs_pos) ) ) ### - Stellar Aberration if not (None is self.obs_vel): ### - Scale observer velocity by reciprocal of the speed of light, ### add result to unit vector toward star. uvinertial = sp.vhat(sp.vadd(uvinertial ,sp.vscl(recip_clight,self.obs_vel) ) ) if self.fovtype == FOV.CIRCLETYPE: ################################################################## ### Compare inertial star vector to circular FOV return sp.vdot(uvinertial,self.uv_cone_axis) >= self.min_cosine,uvinertial assert FOV.POLYGONTYPE == self.fovtype,'Unknown FOV type [{0}]'.format(self.fovtype) #################################################################### ### Compare star vector to polygonal FOV if self.is_convex(): ### Convex FOV: a negative dot product with the inward-pointing ### normal to any side indicates star is outside FOV for inwardnorm in self.inwardsidenorms: if sp.vdot(uvinertial,inwardnorm) < 0.0: return False,uvinertial ### All dot products were non-negative: star is within FOV return True,uvinertial ### Rotate inertial unit vector to local reference frame (reffrm) uvlocalstar = self.rotate_to_local(uvinertial) ### Scale to Z=unity if uvlocalstar[2] < 1e-15: return False,uvinertial z1star = sp.vscl(1.0/uvlocalstar[2],uvlocalstar) ### Setup .localxyzs and .fovsides if None is self.localxyzs: self.setup_localxyzs() ### Count number of crossings of FOV sides count = len([None for fovside in self.fovsides if fovside.right_of(z1star) ]) return ((count&1) and True or False),uvinertial
def to_north(self): if not self.spoint_set: raise SPointNotSetError return spice.vsub(self.north_pole, self.spoint)
def sun_direction(self): if not self.spoint_set: raise SPointNotSetError return spice.vsub(self.center_to_sun.value, self.spoint)
def _get_to_south(self): if not self.spoint_set: raise SPointNotSetError return spice.vsub(self.south_pole, self.spoint)
def _get_sun_direction(self): if not self.spoint_set: raise SPointNotSetError return spice.vsub(self.center_to_sun, self.spoint)