def __init__(self, target, spots = [], resolution = 50): # Constructor. Precomputes ray hits. self.target = target self.resolution = resolution self.spots = spots # make grid of rays R = target.radius res = resolution grid = np.mgrid[ -R:R:res*1j, -R:R:res*1j ] # collide rays with sphere z2 = target.radius**2 - grid[0]**2 - grid[1]**2 hits = (z2 > 0) z = np.sqrt( z2[hits] ) # save positions of hit pixels, and hit locations self.pixels = np.nonzero(hits) self.points = np.vstack([grid[0][hits], grid[1][hits], z]).transpose() # get TV = AV x r, RV = -z . TV angvels = target.angvel(self.points) tangvels = np.cross(angvels, self.points) self.radvels = -tangvels[:,2] # get base luminosity mask from limb darkening norms = np.apply_along_axis(np.linalg.norm, 1, self.points) thetas = np.arccos( self.points[:,2] / norms ) self.base_mask = physics.default_limb_darkening( thetas )
def rv(self, t): # area => spot area # Computes approximate mean RV time t. rv_all = 0 for pos,fracarea in self.spots: pos_t = self.target.evolve(pos, -t) / self.target.radius if pos_t[2] < 0: # behind star continue if hasattr(fracarea, '__call__'): # is fracarea a lambda? theta = geometry.cap_half_angle( fracarea(t) ) else: # or a constant theta = geometry.cap_half_angle( fracarea ) area = math.pi * math.sin(theta)**2 area *= math.sqrt(1 - pos_t[0]**2 - pos_t[1]**2 ) # perspective R = self.target.radius rv = self.max_rv * pos_t[0] ld = physics.default_limb_darkening(math.acos( pos_t[2] )) rv_all -= area * rv * ld return rv_all