コード例 #1
0
ファイル: Observatory.py プロジェクト: ChrisDelaX/EXOSIMS
 def keplerplanet(self, currentTime, bodyname):
     """Finds position vector for solar system objects
     
     This method uses algorithms 2 and 10 from Vallado 2013 to find 
     heliocentric equatorial position vectors (astropy Quantity in km) for 
     solar system objects.
     
     Args:
         currentTime (astropy Time):
             Current absolute mission time in MJD
         bodyname (string):
             Solar system object name
     
     Returns:
         r_body (astropy Quantity nx3 array):
             Heliocentric equatorial position vector in units of km
     
     """
     
     if bodyname == 'Moon':
         r_Earth = self.keplerplanet(currentTime, 'Earth')
         return r_Earth + self.moon_earth(currentTime)
     
     assert self.planets.has_key(bodyname),\
             "%s is not a recognized body name."%(bodyname)
     
     planet = self.planets[bodyname] 
     # find Julian centuries from J2000
     TDB = self.cent(currentTime)
     # update ephemeride data
     a = self.propeph(planet.a, TDB)
     e = self.propeph(planet.e, TDB)
     I = np.radians(self.propeph(planet.I, TDB))
     O = np.radians(self.propeph(planet.O, TDB))
     w = np.radians(self.propeph(planet.w, TDB))
     lM = np.radians(self.propeph(planet.lM, TDB))
     # Find mean anomaly and argument of perigee
     M = np.mod(lM - w,2*np.pi)
     wp = np.mod(w - O,2*np.pi)
     # Find eccentric anomaly
     E = eccanom(M,e)[0]
     # Find true anomaly
     nu = np.arctan2(np.sin(E) * np.sqrt(1 - e**2), np.cos(E) - e)
     # Find semiparameter
     p = a*(1 - e**2)
     # position vector (km) in orbital plane
     rx = p*np.cos(nu)/(1 + e*np.cos(nu))
     ry = p*np.sin(nu)/(1 + e*np.cos(nu))
     rz = np.zeros(currentTime.size)
     r_body = np.vstack((rx,ry,rz))
     # position vector (km) in ecliptic plane
     r_body = np.array([np.dot(np.dot(self.rot(-O[x],3),self.rot(-I[x],1)),\
             np.dot(self.rot(-wp[x],3),r_body[:,x])) for x in range(currentTime.size)]).T
     # find obliquity of the ecliptic
     obe = np.array(np.radians(self.obe(TDB)),ndmin=1)
     # position vector (km) in heliocentric equatorial frame
     r_body = np.array([np.dot(self.rot(-obe[x],1),r_body[:,x])\
             for x in range(currentTime.size)])*u.km
     
     return r_body.to('km')
コード例 #2
0
    def init_systems(self):
        """Finds initial time-dependant parameters. Assigns each planet an 
        initial position, velocity, planet-star distance, apparent separation, 
        phase function, surface brightness of exo-zodiacal light, delta 
        magnitude, and working angle. 
        
        This method makes use of the systems' physical properties (masses, 
        distances) and their orbital elements (a, e, I, O, w, M0).
        
        """

        PPMod = self.PlanetPhysicalModel
        ZL = self.ZodiacalLight
        TL = self.TargetList

        a = self.a.to('AU').value  # semi-major axis
        e = self.e  # eccentricity
        I = self.I.to('rad').value  # inclinations
        O = self.O.to('rad').value  # right ascension of the ascending node
        w = self.w.to('rad').value  # argument of perigee
        M0 = self.M0.to('rad').value  # initial mean anomany
        E = eccanom(M0, e)  # eccentric anomaly
        Mp = self.Mp  # planet masses

        #This is the a1 a2 a3 and b1 b2 b3 are the euler angle transformation from  the I,J,K refernece frame
        # to an x,y,z frame see https://en.wikipedia.org/wiki/Orbital_elements#Keplerian_elements
        a1 = np.cos(O) * np.cos(w) - np.sin(O) * np.cos(I) * np.sin(w)
        a2 = np.sin(O) * np.cos(w) + np.cos(O) * np.cos(I) * np.sin(w)
        a3 = np.sin(I) * np.sin(w)
        A = a * np.vstack((a1, a2, a3)) * u.AU
        b1 = -np.sqrt(1 - e**2) * (np.cos(O) * np.sin(w) +
                                   np.sin(O) * np.cos(I) * np.cos(w))
        b2 = np.sqrt(1 - e**2) * (-np.sin(O) * np.sin(w) +
                                  np.cos(O) * np.cos(I) * np.cos(w))
        b3 = np.sqrt(1 - e**2) * np.sin(I) * np.cos(w)
        B = a * np.vstack((b1, b2, b3)) * u.AU
        r1 = np.cos(E) - e
        r2 = np.sin(E)

        mu = const.G * (Mp + TL.MsTrue[self.plan2star])
        v1 = np.sqrt(mu / self.a**3) / (1 - e * np.cos(E))
        v2 = np.cos(E)

        self.r = (A * r1 + B * r2).T.to('AU')  # position
        self.v = (v1 * (-A * r2 + B * v2)).T.to('AU/day')  # velocity
        self.d = np.linalg.norm(self.r,
                                axis=1) * self.r.unit  # planet-star distance
        self.s = np.linalg.norm(self.r[:, 0:2],
                                axis=1) * self.r.unit  # apparent separation
        self.phi = PPMod.calc_Phi(np.arccos(self.r[:, 2] /
                                            self.d))  # planet phase
        self.fEZ = ZL.fEZ(TL.MV[self.plan2star], self.I,
                          self.d)  # exozodi brightness
        self.dMag = deltaMag(self.p, self.Rp, self.d,
                             self.phi)  # delta magnitude
        self.WA = np.arctan(self.s / TL.dist[self.plan2star]).to(
            'arcsec')  # working angle
コード例 #3
0
 def init_systems(self):
     """Finds initial time-dependant parameters. Assigns each planet an 
     initial position, velocity, planet-star distance, apparent separation, 
     phase function, surface brightness of exo-zodiacal light, delta magnitude, 
     working angle, and initializes the planet current times to zero. 
     This method makes us of the systems' physical properties (masses, distances)
      and their orbital elements (a, e, I, O, w, M0).
     """
     
     PPMod = self.PlanetPhysicalModel
     ZL = self.ZodiacalLight
     TL = self.TargetList
     
     sInds = self.plan2star                  # indices of target stars
     sDist = TL.dist[sInds]                  # distances to target stars
     Ms = TL.MsTrue[sInds]*const.M_sun       # masses of target stars
     
     a = self.a.to('AU').value               # semi-major axis
     e = self.e                              # eccentricity
     I = self.I.to('rad').value              # inclinations
     O = self.O.to('rad').value              # right ascension of the ascending node
     w = self.w.to('rad').value              # argument of perigee
     M0 = self.M0.to('rad').value            # initial mean anomany
     E = eccanom(M0, e)                      # eccentric anomaly
     Mp = self.Mp                            # planet masses
     
     a1 = np.cos(O)*np.cos(w) - np.sin(O)*np.cos(I)*np.sin(w)
     a2 = np.sin(O)*np.cos(w) + np.cos(O)*np.cos(I)*np.sin(w)
     a3 = np.sin(I)*np.sin(w)
     A = a*np.vstack((a1,a2,a3))*u.AU
     b1 = -np.sqrt(1.-e**2)*(np.cos(O)*np.sin(w) + np.sin(O)*np.cos(I)*np.cos(w))
     b2 = np.sqrt(1.-e**2)*(-np.sin(O)*np.sin(w) + np.cos(O)*np.cos(I)*np.cos(w))
     b3 = np.sqrt(1.-e**2)*np.sin(I)*np.cos(w)
     B = a*np.vstack((b1,b2,b3))*u.AU
     
     r1 = np.cos(E) - e
     r2 = np.sin(E)
     mu = const.G*(Mp + Ms)
     v1 = np.sqrt(mu/self.a**3)/(1. - e*np.cos(E))
     v2 = np.cos(E)
     
     self.r = (A*r1 + B*r2).T.to('AU')                       # position
     self.v = (v1*(-A*r2 + B*v2)).T.to('AU/day')             # velocity
     self.d = np.sqrt(np.sum(self.r**2, axis=1))             # planet-star distance
     self.s = np.sqrt(np.sum(self.r[:,0:2]**2, axis=1))      # apparent separation
     self.phi = PPMod.calc_Phi(np.arcsin(self.s/self.d))     # planet phase
     self.fEZ = ZL.fEZ(TL, sInds, self.I, self.d)            # exozodi brightness
     self.dMag = deltaMag(self.p, self.Rp, self.d, self.phi) # delta magnitude
     self.WA = np.arctan(self.s/sDist).to('mas')             # working angle
     # current time (normalized to zero at mission start) of planet positions
     self.planTime = np.zeros(self.nPlans)*u.day
コード例 #4
0
 def init_systems(self):
     """Finds initial time-dependant parameters. Assigns each planet an 
     initial position, velocity, planet-star distance, apparent separation, 
     phase function, surface brightness of exo-zodiacal light, delta 
     magnitude, and working angle. 
     
     This method makes use of the systems' physical properties (masses, 
     distances) and their orbital elements (a, e, I, O, w, M0).
     
     """
     
     PPMod = self.PlanetPhysicalModel
     ZL = self.ZodiacalLight
     TL = self.TargetList
     
     a = self.a.to('AU').value               # semi-major axis
     e = self.e                              # eccentricity
     I = self.I.to('rad').value              # inclinations
     O = self.O.to('rad').value              # right ascension of the ascending node
     w = self.w.to('rad').value              # argument of perigee
     M0 = self.M0.to('rad').value            # initial mean anomany
     E = eccanom(M0, e)                      # eccentric anomaly
     Mp = self.Mp                            # planet masses
     
     a1 = np.cos(O)*np.cos(w) - np.sin(O)*np.cos(I)*np.sin(w)
     a2 = np.sin(O)*np.cos(w) + np.cos(O)*np.cos(I)*np.sin(w)
     a3 = np.sin(I)*np.sin(w)
     A = a*np.vstack((a1, a2, a3))*u.AU
     b1 = -np.sqrt(1 - e**2)*(np.cos(O)*np.sin(w) + np.sin(O)*np.cos(I)*np.cos(w))
     b2 = np.sqrt(1 - e**2)*(-np.sin(O)*np.sin(w) + np.cos(O)*np.cos(I)*np.cos(w))
     b3 = np.sqrt(1 - e**2)*np.sin(I)*np.cos(w)
     B = a*np.vstack((b1, b2, b3))*u.AU
     r1 = np.cos(E) - e
     r2 = np.sin(E)
     
     mu = const.G*(Mp + TL.MsTrue[self.plan2star])
     v1 = np.sqrt(mu/self.a**3)/(1 - e*np.cos(E))
     v2 = np.cos(E)
     
     self.r = (A*r1 + B*r2).T.to('AU')                           # position
     self.v = (v1*(-A*r2 + B*v2)).T.to('AU/day')                 # velocity
     self.d = np.linalg.norm(self.r, axis=1)*self.r.unit         # planet-star distance
     self.s = np.linalg.norm(self.r[:,0:2], axis=1)*self.r.unit  # apparent separation
     self.phi = PPMod.calc_Phi(np.arccos(self.r[:,2]/self.d))    # planet phase
     self.fEZ = ZL.fEZ(TL.MV[self.plan2star], self.I, self.d)    # exozodi brightness
     self.dMag = deltaMag(self.p, self.Rp, self.d, self.phi)     # delta magnitude
     self.WA = np.arctan(self.s/TL.dist[self.plan2star]).to('arcsec')# working angle
コード例 #5
0
    def genplans(self, nplan):
        """Generates planet data needed for Monte Carlo simulation
        
        Args:
            nplan (integer):
                Number of planets
                
        Returns:
            tuple:
            s (astropy Quantity array):
                Planet apparent separations in units of AU
            dMag (ndarray):
                Difference in brightness
        
        """
        
        PPop = self.PlanetPopulation
        
        nplan = int(nplan)
        
        # sample uniform distribution of mean anomaly
        M = np.random.uniform(high=2.0*np.pi,size=nplan)
        # sample quantities
        a, e, p, Rp = PPop.gen_plan_params(nplan)
        # check if circular orbits
        if np.sum(PPop.erange) == 0:
            r = a
            e = 0.0
            E = M
        else:
            E = eccanom(M,e)
            # orbital radius
            r = a*(1.0-e*np.cos(E))

        beta = np.arccos(1.0-2.0*np.random.uniform(size=nplan))*u.rad
        s = r*np.sin(beta)
        # phase function
        Phi = self.PlanetPhysicalModel.calc_Phi(beta)
        # calculate dMag
        dMag = deltaMag(p,Rp,r,Phi)
        
        return s, dMag
コード例 #6
0
ファイル: BrownCompleteness.py プロジェクト: jrenrut/EXOSIMS
    def genplans(self, nplan):
        """Generates planet data needed for Monte Carlo simulation
        
        Args:
            nplan (integer):
                Number of planets
                
        Returns:
            tuple:
            s (astropy Quantity array):
                Planet apparent separations in units of AU
            dMag (ndarray):
                Difference in brightness
        
        """

        PPop = self.PlanetPopulation

        nplan = int(nplan)

        # sample uniform distribution of mean anomaly
        M = np.random.uniform(high=2.0 * np.pi, size=nplan)
        # sample quantities
        a, e, p, Rp = PPop.gen_plan_params(nplan)
        # check if circular orbits
        if np.sum(PPop.erange) == 0:
            r = a
            e = 0.0
            E = M
        else:
            E = eccanom(M, e)
            # orbital radius
            r = a * (1.0 - e * np.cos(E))

        beta = np.arccos(1.0 - 2.0 * np.random.uniform(size=nplan)) * u.rad
        s = r * np.sin(beta)
        # phase function
        Phi = self.PlanetPhysicalModel.calc_Phi(beta)
        # calculate dMag
        dMag = deltaMag(p, Rp, r, Phi)

        return s, dMag
コード例 #7
0
ファイル: BrownCompleteness.py プロジェクト: jrenrut/EXOSIMS
    def gen_update(self, TL):
        """Generates dynamic completeness values for multiple visits of each 
        star in the target list
        
        Args:
            TL (TargetList):
                TargetList class object
        
        """

        OS = TL.OpticalSystem
        PPop = TL.PlanetPopulation

        # limiting planet delta magnitude for completeness
        dMagMax = self.dMagLim

        # get name for stored dynamic completeness updates array
        # inner and outer working angles for detection mode
        mode = list(
            filter(lambda mode: mode['detectionMode'] == True,
                   OS.observingModes))[0]
        IWA = mode['IWA']
        OWA = mode['OWA']
        extstr = self.extstr + 'IWA: ' + str(IWA) + ' OWA: ' + str(OWA) + \
                ' dMagMax: ' + str(dMagMax) + ' nStars: ' + str(TL.nStars)
        ext = hashlib.md5(extstr.encode('utf-8')).hexdigest()
        self.dfilename += ext
        self.dfilename += '.dcomp'

        path = os.path.join(self.cachedir, self.dfilename)
        # if the 2D completeness update array exists as a .dcomp file load it
        if os.path.exists(path):
            self.vprint(
                'Loading cached dynamic completeness array from "%s".' % path)
            try:
                with open(path, "rb") as ff:
                    self.updates = pickle.load(ff)
            except UnicodeDecodeError:
                with open(path, "rb") as ff:
                    self.updates = pickle.load(ff, encoding='latin1')
            self.vprint('Dynamic completeness array loaded from cache.')
        else:
            # run Monte Carlo simulation and pickle the resulting array
            self.vprint(
                'Cached dynamic completeness array not found at "%s".' % path)
            self.vprint('Beginning dynamic completeness calculations')
            # dynamic completeness values: rows are stars, columns are number of visits
            self.updates = np.zeros((TL.nStars, 5))
            # number of planets to simulate
            nplan = int(2e4)
            # sample quantities which do not change in time
            a, e, p, Rp = PPop.gen_plan_params(nplan)
            a = a.to('AU').value
            # sample angles
            I, O, w = PPop.gen_angles(nplan)
            I = I.to('rad').value
            O = O.to('rad').value
            w = w.to('rad').value
            Mp = PPop.gen_mass(nplan)  # M_earth
            rmax = a * (1. + e)  # AU
            # sample quantity which will be updated
            M = np.random.uniform(high=2. * np.pi, size=nplan)
            newM = np.zeros((nplan, ))
            # population values
            smin = (np.tan(IWA) * TL.dist).to('AU').value
            if np.isfinite(OWA):
                smax = (np.tan(OWA) * TL.dist).to('AU').value
            else:
                smax = np.array([np.max(PPop.arange.to('AU').value)*\
                        (1.+np.max(PPop.erange))]*TL.nStars)
            # fill dynamic completeness values
            for sInd in xrange(TL.nStars):
                mu = (const.G * (Mp + TL.MsTrue[sInd])).to('AU3/day2').value
                n = np.sqrt(mu / a**3)  # in 1/day
                # normalization time equation from Brown 2015
                dt = 58.0 * (TL.L[sInd] / 0.83)**(3.0 / 4.0) * (
                    TL.MsTrue[sInd] / (0.91 * u.M_sun))**(1.0 / 2.0)  # days
                # remove rmax < smin
                pInds = np.where(rmax > smin[sInd])[0]
                # calculate for 5 successive observations
                for num in xrange(5):
                    if num == 0:
                        self.updates[sInd, num] = TL.comp0[sInd]
                    if not pInds.any():
                        break
                    # find Eccentric anomaly
                    if num == 0:
                        E = eccanom(M[pInds], e[pInds])
                        newM[pInds] = M[pInds]
                    else:
                        E = eccanom(newM[pInds], e[pInds])

                    r1 = a[pInds] * (np.cos(E) - e[pInds])
                    r1 = np.hstack(
                        (r1.reshape(len(r1),
                                    1), r1.reshape(len(r1),
                                                   1), r1.reshape(len(r1), 1)))
                    r2 = (a[pInds] * np.sin(E) * np.sqrt(1. - e[pInds]**2))
                    r2 = np.hstack(
                        (r2.reshape(len(r2),
                                    1), r2.reshape(len(r2),
                                                   1), r2.reshape(len(r2), 1)))

                    a1 = np.cos(O[pInds]) * np.cos(w[pInds]) - np.sin(
                        O[pInds]) * np.sin(w[pInds]) * np.cos(I[pInds])
                    a2 = np.sin(O[pInds]) * np.cos(w[pInds]) + np.cos(
                        O[pInds]) * np.sin(w[pInds]) * np.cos(I[pInds])
                    a3 = np.sin(w[pInds]) * np.sin(I[pInds])
                    A = np.hstack(
                        (a1.reshape(len(a1),
                                    1), a2.reshape(len(a2),
                                                   1), a3.reshape(len(a3), 1)))

                    b1 = -np.cos(O[pInds]) * np.sin(w[pInds]) - np.sin(
                        O[pInds]) * np.cos(w[pInds]) * np.cos(I[pInds])
                    b2 = -np.sin(O[pInds]) * np.sin(w[pInds]) + np.cos(
                        O[pInds]) * np.cos(w[pInds]) * np.cos(I[pInds])
                    b3 = np.cos(w[pInds]) * np.sin(I[pInds])
                    B = np.hstack(
                        (b1.reshape(len(b1),
                                    1), b2.reshape(len(b2),
                                                   1), b3.reshape(len(b3), 1)))

                    # planet position, planet-star distance, apparent separation
                    r = (A * r1 + B * r2)  # position vector (AU)
                    d = np.linalg.norm(r, axis=1)  # planet-star distance
                    s = np.linalg.norm(r[:, 0:2],
                                       axis=1)  # apparent separation
                    beta = np.arccos(r[:, 2] / d)  # phase angle
                    Phi = self.PlanetPhysicalModel.calc_Phi(
                        beta * u.rad)  # phase function
                    dMag = deltaMag(p[pInds], Rp[pInds], d * u.AU,
                                    Phi)  # difference in magnitude

                    toremoves = np.where((s > smin[sInd])
                                         & (s < smax[sInd]))[0]
                    toremovedmag = np.where(dMag < dMagMax)[0]
                    toremove = np.intersect1d(toremoves, toremovedmag)

                    pInds = np.delete(pInds, toremove)

                    if num == 0:
                        self.updates[sInd, num] = TL.comp0[sInd]
                    else:
                        self.updates[sInd, num] = float(len(toremove)) / nplan

                    # update M
                    newM[pInds] = (newM[pInds] + n[pInds] * dt) / (
                        2 * np.pi) % 1 * 2. * np.pi

                if (sInd + 1) % 50 == 0:
                    self.vprint('stars: %r / %r' % (sInd + 1, TL.nStars))
            # ensure that completeness values are between 0 and 1
            self.updates = np.clip(self.updates, 0., 1.)
            # store dynamic completeness array as .dcomp file
            with open(path, 'wb') as ff:
                pickle.dump(self.updates, ff)
            self.vprint('Dynamic completeness calculations finished')
            self.vprint('Dynamic completeness array stored in %r' % path)
コード例 #8
0
 def genplans(self, nplan):
     """Generates planet data needed for Monte Carlo simulation
     
     Args:
         nplan (integer):
             Number of planets
             
     Returns:
         s (astropy Quantity array):
             Planet apparent separations in units of AU
         dMag (ndarray):
             Difference in brightness
     
     """
     nplan = int(nplan)
     
     # sample uniform distribution of mean anomaly
     M = np.random.uniform(high=2.*np.pi,size=nplan)
     # sample semi-major axis        
     a = self.PlanetPopulation.gen_sma(nplan).to('AU').value
     
     # sample other necessary orbital parameters
     if np.sum(self.PlanetPopulation.erange) == 0:
         # all circular orbits
         r = a
         e = 0.
         E = M
     else:
         # sample eccentricity
         if self.PlanetPopulation.constrainOrbits:
             e = self.PlanetPopulation.gen_eccen_from_sma(nplan,a*u.AU)
         else:
             e = self.PlanetPopulation.gen_eccen(nplan)   
         # Newton-Raphson to find E
         E = eccanom(M,e)
         # orbital radius
         r = a*(1-e*np.cos(E))
     
     # orbit angle sampling
     O = self.PlanetPopulation.gen_O(nplan).to('rad').value
     w = self.PlanetPopulation.gen_w(nplan).to('rad').value
     I = self.PlanetPopulation.gen_I(nplan).to('rad').value
     
     r1 = r*(np.cos(E) - e)
     r1 = np.hstack((r1.reshape(len(r1),1), r1.reshape(len(r1),1), r1.reshape(len(r1),1)))
     r2 = r*np.sin(E)*np.sqrt(1. -  e**2)
     r2 = np.hstack((r2.reshape(len(r2),1), r2.reshape(len(r2),1), r2.reshape(len(r2),1)))
     
     a1 = np.cos(O)*np.cos(w) - np.sin(O)*np.sin(w)*np.cos(I)
     a2 = np.sin(O)*np.cos(w) + np.cos(O)*np.sin(w)*np.cos(I)
     a3 = np.sin(w)*np.sin(I)
     A = np.hstack((a1.reshape(len(a1),1), a2.reshape(len(a2),1), a3.reshape(len(a3),1)))
     
     b1 = -np.cos(O)*np.sin(w) - np.sin(O)*np.cos(w)*np.cos(I)
     b2 = -np.sin(O)*np.sin(w) + np.cos(O)*np.cos(w)*np.cos(I)
     b3 = np.cos(w)*np.sin(I)
     B = np.hstack((b1.reshape(len(b1),1), b2.reshape(len(b2),1), b3.reshape(len(b3),1)))
     
     # planet position, planet-star distance, apparent separation
     r = (A*r1 + B*r2)*u.AU
     d = np.sqrt(np.sum(r**2, axis=1))
     s = np.sqrt(np.sum(r[:,0:2]**2, axis=1))
     
     # sample albedo, planetary radius, phase function
     p = self.PlanetPopulation.gen_albedo(nplan)
     Rp = self.PlanetPopulation.gen_radius(nplan)
     beta = np.arccos(r[:,2]/d)
     Phi = self.PlanetPhysicalModel.calc_Phi(beta)
     
     # calculate dMag
     dMag = deltaMag(p,Rp,d,Phi)
     
     return s, dMag
コード例 #9
0
 def gen_update(self, targlist):
     """Generates dynamic completeness values for multiple visits of each 
     star in the target list
     
     Args:
         targlist (TargetList):
             TargetList module
     
     """
     
     print 'Beginning completeness update calculations'
     self.visits = np.array([0]*targlist.nStars)
     self.updates = []
     # number of planets to simulate
     nplan = int(2e4)
     # normalization time
     dt = 1e9*u.day
     # sample quantities which do not change in time
     a = self.PlanetPopulation.gen_sma(nplan) # AU
     e = self.PlanetPopulation.gen_eccen(nplan)
     I = self.PlanetPopulation.gen_I(nplan) # deg
     O = self.PlanetPopulation.gen_O(nplan) # deg
     w = self.PlanetPopulation.gen_w(nplan) # deg
     p = self.PlanetPopulation.gen_albedo(nplan)
     Rp = self.PlanetPopulation.gen_radius(nplan) # km
     Mp = self.PlanetPopulation.gen_mass(nplan) # kg
     rmax = a*(1.+e)
     rmin = a*(1.-e)
     # sample quantity which will be updated
     M = np.random.uniform(high=2.*np.pi,size=nplan)
     newM = np.zeros((nplan,))
     # population values
     smin = (np.tan(targlist.OpticalSystem.IWA)*targlist.dist).to('AU')
     if np.isfinite(targlist.OpticalSystem.OWA):
         smax = (np.tan(targlist.OpticalSystem.OWA)*targlist.dist).to('AU')
     else:
         smax = np.array([np.max(self.PlanetPopulation.arange.to('AU').value)*\
                 (1.+np.max(self.PlanetPopulation.erange))]*targlist.nStars)*u.AU
     # fill dynamic completeness values
     for sInd in xrange(targlist.nStars):
         Mstar = targlist.MsTrue[sInd]*const.M_sun
         # remove rmax < smin and rmin > smax
         inside = np.where(rmax > smin[sInd])[0]
         outside = np.where(rmin < smax[sInd])[0]
         pInds = np.intersect1d(inside,outside)
         dynamic = []
         # calculate for 5 successive observations
         for num in xrange(5):
             if not pInds.any():
                 dynamic.append(0.)
                 break
             # find Eccentric anomaly
             if num == 0:
                 E = eccanom(M[pInds],e[pInds])
                 newM[pInds] = M[pInds]
             else:
                 E = eccanom(newM[pInds],e[pInds])
             
             r = a[pInds]*(1.-e[pInds]*np.cos(E))
             r1 = r*(np.cos(E) - e[pInds])
             r1 = np.hstack((r1.reshape(len(r1),1), r1.reshape(len(r1),1), r1.reshape(len(r1),1)))
             r2 = (r*np.sin(E)*np.sqrt(1. -  e[pInds]**2))
             r2 = np.hstack((r2.reshape(len(r2),1), r2.reshape(len(r2),1), r2.reshape(len(r2),1)))
             
             a1 = np.cos(O[pInds])*np.cos(w[pInds]) - np.sin(O[pInds])*np.sin(w[pInds])*np.cos(I[pInds])
             a2 = np.sin(O[pInds])*np.cos(w[pInds]) + np.cos(O[pInds])*np.sin(w[pInds])*np.cos(I[pInds])
             a3 = np.sin(w[pInds])*np.sin(I[pInds])
             A = np.hstack((a1.reshape(len(a1),1), a2.reshape(len(a2),1), a3.reshape(len(a3),1)))
             
             b1 = -np.cos(O[pInds])*np.sin(w[pInds]) - np.sin(O[pInds])*np.cos(w[pInds])*np.cos(I[pInds])
             b2 = -np.sin(O[pInds])*np.sin(w[pInds]) + np.cos(O[pInds])*np.cos(w[pInds])*np.cos(I[pInds])
             b3 = np.cos(w[pInds])*np.sin(I[pInds])
             B = np.hstack((b1.reshape(len(b1),1), b2.reshape(len(b2),1), b3.reshape(len(b3),1)))
             
             # planet position, planet-star distance, apparent separation
             r = (A*r1 + B*r2)*u.AU # position vector
             d = np.sqrt(np.sum(r**2, axis=1)) # planet-star distance
             s = np.sqrt(np.sum(r[:,0:2]**2, axis=1)) # apparent separation
             beta = np.arccos(r[:,2]/d) # phase angle
             Phi = self.PlanetPhysicalModel.calc_Phi(beta) # phase function
             dMag = deltaMag(p[pInds],Rp[pInds],d,Phi) # difference in magnitude
             
             toremoves = np.where((s > smin[sInd]) & (s < smax[sInd]))[0]
             toremovedmag = np.where(dMag < targlist.OpticalSystem.dMagLim)[0]
             toremove = np.intersect1d(toremoves, toremovedmag)
             
             pInds = np.delete(pInds, toremove)
             
             if num == 0:
                 dynamic.append(targlist.comp0[sInd])
             else:
                 dynamic.append(float(len(toremove))/nplan)
             
             # update M
             mu = const.G*(Mstar+Mp[pInds])
             n = np.sqrt(mu/a[pInds]**3)
             newM[pInds] = (newM[pInds] + n*dt)/(2*np.pi) % 1 * 2.*np.pi
         
         self.updates.append(dynamic)
             
         if (sInd+1) % 50 == 0:
             print 'stars: %r / %r' % (sInd+1,targlist.nStars)
     
     self.updates = np.array(self.updates)
     print 'Completeness update calculations finished'
コード例 #10
0
    def genplans(self, nplan):
        """Generates planet data needed for Monte Carlo simulation
        
        Args:
            nplan (integer):
                Number of planets
                
        Returns:
            s (astropy Quantity array):
                Planet apparent separations in units of AU
            dMag (ndarray):
                Difference in brightness
        
        """

        PPop = self.PlanetPopulation

        nplan = int(nplan)

        # sample uniform distribution of mean anomaly
        M = np.random.uniform(high=2. * np.pi, size=nplan)
        # sample semi-major axis
        a = PPop.gen_sma(nplan).to('AU').value

        # sample other necessary orbital parameters
        if np.sum(PPop.erange) == 0:
            # all circular orbits
            r = a
            e = 0.
            E = M
        else:
            # sample eccentricity
            if PPop.constrainOrbits:
                e = PPop.gen_eccen_from_sma(nplan, a * u.AU)
            else:
                e = PPop.gen_eccen(nplan)
            # Newton-Raphson to find E
            E = eccanom(M, e)
            # orbital radius
            r = a * (1 - e * np.cos(E))

        # orbit angle sampling
        O = PPop.gen_O(nplan).to('rad').value
        w = PPop.gen_w(nplan).to('rad').value
        I = PPop.gen_I(nplan).to('rad').value

        r1 = a * (np.cos(E) - e)
        r1 = np.hstack((r1.reshape(len(r1),
                                   1), r1.reshape(len(r1),
                                                  1), r1.reshape(len(r1), 1)))
        r2 = a * np.sin(E) * np.sqrt(1. - e**2)
        r2 = np.hstack((r2.reshape(len(r2),
                                   1), r2.reshape(len(r2),
                                                  1), r2.reshape(len(r2), 1)))

        a1 = np.cos(O) * np.cos(w) - np.sin(O) * np.sin(w) * np.cos(I)
        a2 = np.sin(O) * np.cos(w) + np.cos(O) * np.sin(w) * np.cos(I)
        a3 = np.sin(w) * np.sin(I)
        A = np.hstack((a1.reshape(len(a1),
                                  1), a2.reshape(len(a2),
                                                 1), a3.reshape(len(a3), 1)))

        b1 = -np.cos(O) * np.sin(w) - np.sin(O) * np.cos(w) * np.cos(I)
        b2 = -np.sin(O) * np.sin(w) + np.cos(O) * np.cos(w) * np.cos(I)
        b3 = np.cos(w) * np.sin(I)
        B = np.hstack((b1.reshape(len(b1),
                                  1), b2.reshape(len(b2),
                                                 1), b3.reshape(len(b3), 1)))

        # planet position, planet-star distance, apparent separation
        r = (A * r1 + B * r2) * u.AU
        d = np.sqrt(np.sum(r**2, axis=1))
        s = np.sqrt(np.sum(r[:, 0:2]**2, axis=1))

        # sample albedo, planetary radius, phase function
        p = PPop.gen_albedo(nplan)
        Rp = PPop.gen_radius(nplan)
        beta = np.arccos(r[:, 2] / d)
        Phi = self.PlanetPhysicalModel.calc_Phi(beta)

        # calculate dMag
        dMag = deltaMag(p, Rp, d, Phi)

        return s, dMag
コード例 #11
0
    def gen_update(self, TL):
        """Generates dynamic completeness values for multiple visits of each 
        star in the target list
        
        Args:
            TL (TargetList module):
                TargetList class object
        
        """

        OS = TL.OpticalSystem
        PPop = self.PlanetPopulation

        print 'Beginning completeness update calculations'
        # initialize number of visits
        self.visits = np.array([0] * TL.nStars)
        # dynamic completeness values: rows are stars, columns are number of visits
        self.updates = np.zeros((TL.nStars, 5))
        # number of planets to simulate
        nplan = int(2e4)
        # normalization time
        dt = 1e9 * u.day
        # sample quantities which do not change in time
        a = PPop.gen_sma(nplan)  # AU
        e = PPop.gen_eccen(nplan)
        I = PPop.gen_I(nplan)  # deg
        O = PPop.gen_O(nplan)  # deg
        w = PPop.gen_w(nplan)  # deg
        p = PPop.gen_albedo(nplan)
        Rp = PPop.gen_radius(nplan)  # km
        Mp = PPop.gen_mass(nplan)  # kg
        rmax = a * (1. + e)
        # sample quantity which will be updated
        M = np.random.uniform(high=2. * np.pi, size=nplan)
        newM = np.zeros((nplan, ))
        # population values
        smin = (np.tan(OS.IWA) * TL.dist).to('AU')
        if np.isfinite(OS.OWA):
            smax = (np.tan(OS.OWA) * TL.dist).to('AU')
        else:
            smax = np.array([np.max(PPop.arange.to('AU').value)*\
                    (1.+np.max(PPop.erange))]*TL.nStars)*u.AU
        # fill dynamic completeness values
        for sInd in xrange(TL.nStars):
            Mstar = TL.MsTrue[sInd] * const.M_sun
            # remove rmax < smin
            pInds = np.where(rmax > smin[sInd])[0]
            # calculate for 5 successive observations
            for num in xrange(5):
                if num == 0:
                    self.updates[sInd, num] = TL.comp0[sInd]
                if not pInds.any():
                    break
                # find Eccentric anomaly
                if num == 0:
                    E = eccanom(M[pInds], e[pInds])
                    newM[pInds] = M[pInds]
                else:
                    E = eccanom(newM[pInds], e[pInds])

                r1 = a[pInds] * (np.cos(E) - e[pInds])
                r1 = np.hstack((r1.reshape(len(r1), 1), r1.reshape(len(r1), 1),
                                r1.reshape(len(r1), 1)))
                r2 = (a[pInds] * np.sin(E) * np.sqrt(1. - e[pInds]**2))
                r2 = np.hstack((r2.reshape(len(r2), 1), r2.reshape(len(r2), 1),
                                r2.reshape(len(r2), 1)))

                a1 = np.cos(O[pInds]) * np.cos(w[pInds]) - np.sin(
                    O[pInds]) * np.sin(w[pInds]) * np.cos(I[pInds])
                a2 = np.sin(O[pInds]) * np.cos(w[pInds]) + np.cos(
                    O[pInds]) * np.sin(w[pInds]) * np.cos(I[pInds])
                a3 = np.sin(w[pInds]) * np.sin(I[pInds])
                A = np.hstack((a1.reshape(len(a1), 1), a2.reshape(len(a2), 1),
                               a3.reshape(len(a3), 1)))

                b1 = -np.cos(O[pInds]) * np.sin(w[pInds]) - np.sin(
                    O[pInds]) * np.cos(w[pInds]) * np.cos(I[pInds])
                b2 = -np.sin(O[pInds]) * np.sin(w[pInds]) + np.cos(
                    O[pInds]) * np.cos(w[pInds]) * np.cos(I[pInds])
                b3 = np.cos(w[pInds]) * np.sin(I[pInds])
                B = np.hstack((b1.reshape(len(b1), 1), b2.reshape(len(b2), 1),
                               b3.reshape(len(b3), 1)))

                # planet position, planet-star distance, apparent separation
                r = (A * r1 + B * r2) * u.AU  # position vector
                d = np.sqrt(np.sum(r**2, axis=1))  # planet-star distance
                s = np.sqrt(np.sum(r[:, 0:2]**2,
                                   axis=1))  # apparent separation
                beta = np.arccos(r[:, 2] / d)  # phase angle
                Phi = self.PlanetPhysicalModel.calc_Phi(beta)  # phase function
                dMag = deltaMag(p[pInds], Rp[pInds], d,
                                Phi)  # difference in magnitude

                toremoves = np.where((s > smin[sInd]) & (s < smax[sInd]))[0]
                toremovedmag = np.where(dMag < OS.dMagLim)[0]
                toremove = np.intersect1d(toremoves, toremovedmag)

                pInds = np.delete(pInds, toremove)

                if num == 0:
                    self.updates[sInd, num] = TL.comp0[sInd]
                else:
                    self.updates[sInd, num] = float(len(toremove)) / nplan

                # update M
                mu = const.G * (Mstar + Mp[pInds])
                n = np.sqrt(mu / a[pInds]**3)
                newM[pInds] = (newM[pInds] + n * dt) / (2 *
                                                        np.pi) % 1 * 2. * np.pi

            if (sInd + 1) % 50 == 0:
                print 'stars: %r / %r' % (sInd + 1, TL.nStars)

        print 'Completeness update calculations finished'
コード例 #12
0
ファイル: test_eccanom.py プロジェクト: dsavransky/EXOSIMS
    def test_eccanom(self):
        r"""Test eccentric anomaly computation.

        Approach: Reference to pre-computed results from Matlab, plus
        additional check that solutions satisfy Kepler's equation.
        Tests restricted to eccentricity between 0.0 and 0.4."""

        # eccanom() appears to be a specialized version of newtonm.m from
        # Vallado's m-files.  eccanom() implements the case in the m-file
        # marked "elliptical", because it works for planets in elliptical orbits.

        print('eccanom()')

        # precomputed from newtonm.m in Vallado's Matlab source code
        tabulation = {
            # a few systematically-chosen values, a few random ones
            # (eccentricity in [0,0.4] and mean anomaly in [0,2 pi]
            # label    eccentricity     mean anomaly    ecc-anomaly    true-anomaly
            "syst-0":  (0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000),
            "syst-1":  (0.025000000000, 0.400000000000, 0.409964417354, 0.420045901819),
            "syst-2":  (0.050000000000, 0.800000000000, 0.837136437398, 0.874924655639),
            "syst-3":  (0.075000000000, 1.200000000000, 1.271669563802, 1.344211492229),
            "syst-4":  (0.100000000000, 1.600000000000, 1.699177050713, 1.797889059320),
            "syst-5":  (0.125000000000, 2.000000000000, 2.107429361800, 2.211834518809),
            "syst-6":  (0.150000000000, 2.400000000000, 2.490864846892, 2.577019718783),
            "syst-7":  (0.175000000000, 2.800000000000, 2.850264344358, 2.896965705233),
            "syst-8":  (0.200000000000, 3.200000000000, 3.190268645286, -3.101846256861),
            "syst-9":  (0.225000000000, 3.600000000000, 3.517416263407, -2.841371075544),
            "syst-10": (0.250000000000, 4.000000000000, 3.839370814447, -2.592284710937),
            "syst-11": (0.275000000000, 4.400000000000, 4.165158556909, -2.340284012237),
            "syst-12": (0.300000000000, 4.800000000000, 4.506345584831, -2.066225859687),
            "syst-13": (0.325000000000, 5.200000000000, 4.879529007461, -1.739297079458),
            "syst-14": (0.350000000000, 5.600000000000, 5.310823513733, -1.301816690532),
            "syst-15": (0.375000000000, 6.000000000000, 5.838779417089, -0.646704214263),
            "rand-1":  (0.021228232647, 5.868452651315, 5.859729688192, -0.432264760951),
            "rand-2":  (0.016968378871, 4.761021655110, 4.744061786583, -1.556088761716),
            "rand-3":  (0.018578311703, 2.464435046216, 2.475908955821, 2.487300499232),
            "rand-4":  (0.016386947254, 1.075597681642, 1.090127758250, 1.104713814823),
            "rand-5":  (0.017651152200, 0.200011672644, 0.203580329847, 0.207180380010),
            "rand-6":  (0.006923074624, 0.290103403226, 0.292096978801, 0.294097208267),
            "rand-7":  (0.002428294531, 5.173938128028, 5.171761572640, -1.113601464490),
            "rand-8":  (0.017370715574, 1.992394794033, 2.008130645020, 2.023809681520),
            "rand-9":  (0.023755551221, 0.216431106906, 0.221653600172, 0.226938058952),
            "rand-10": (0.010968608991, 2.397402491437, 2.404772696274, 2.412113273400),
            "rand-11": (0.019137919704, 4.996388335095, 4.977921138154, -1.323779018431),
            "rand-12": (0.004671815114, 3.077280455596, 3.077579312617, 3.077877470783),
            "rand-13": (0.011139655018, 4.060904408970, 4.052106100441, -2.239847775747),
            "rand-14": (0.017734120771, 4.741836271756, 4.724103367769, -1.576817615338),
            "rand-15": (0.006900626925, 4.270697872458, 4.264477964900, -2.024918020450),
            "rand-16": (0.016377450099, 1.021719665350, 1.035808775845, 1.049957669774),
            "rand-17": (0.002974942039, 3.131313689041, 3.131344177237, 3.131374620007),
            "rand-18": (0.023993598963, 2.138706596562, 2.158672164638, 2.178507958606),
            "rand-19": (0.014631693774, 1.406251889782, 1.420719116738, 1.435202708137),
            "rand-20": (0.018781676483, 1.602809881387, 1.621567356335, 1.640316999728),
            }

        for (_, value) in tabulation.items():
            (ref_eccentricity, ref_mean_anomaly, ref_ecc_anomaly, _ref_true_anomaly) = value
            exo_ecc_anomaly = eccanom(ref_mean_anomaly, ref_eccentricity)
            # 1: ensure the output agrees with the tabulation
            self.assertAlmostEqual(exo_ecc_anomaly, ref_ecc_anomaly, delta=1e-6)
            # 2: additionally, ensure the Kepler relation:
            #   M = E - e sin E
            # is satisfied for the output of eccanom().
            # Here, e is the given eccentricity, E is the EXOSIMS eccentric
            # anomaly, and M is the mean anomaly.
            est_mean_anomaly = exo_ecc_anomaly - ref_eccentricity * np.sin(exo_ecc_anomaly)
            self.assertAlmostEqual(ref_mean_anomaly, est_mean_anomaly, delta=1e-6)
コード例 #13
0
    def test_eccanom(self):
        r"""Test eccentric anomaly computation.

        Approach: Reference to pre-computed results from Matlab, plus
        additional check that solutions satisfy Kepler's equation.
        Tests restricted to eccentricity between 0.0 and 0.4."""

        # eccanom() appears to be a specialized version of newtonm.m from
        # Vallado's m-files.  eccanom() implements the case in the m-file
        # marked "elliptical", because it works for planets in elliptical orbits.

        print 'eccanom()'

        # precomputed from newtonm.m in Vallado's Matlab source code
        tabulation = {
            # a few systematically-chosen values, a few random ones
            # (eccentricity in [0,0.4] and mean anomaly in [0,2 pi]
            # label    eccentricity     mean anomaly    ecc-anomaly    true-anomaly
            "syst-0":
            (0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000),
            "syst-1":
            (0.025000000000, 0.400000000000, 0.409964417354, 0.420045901819),
            "syst-2":
            (0.050000000000, 0.800000000000, 0.837136437398, 0.874924655639),
            "syst-3":
            (0.075000000000, 1.200000000000, 1.271669563802, 1.344211492229),
            "syst-4": (0.100000000000, 1.600000000000, 1.699177050713,
                       1.797889059320),
            "syst-5": (0.125000000000, 2.000000000000, 2.107429361800,
                       2.211834518809),
            "syst-6": (0.150000000000, 2.400000000000, 2.490864846892,
                       2.577019718783),
            "syst-7": (0.175000000000, 2.800000000000, 2.850264344358,
                       2.896965705233),
            "syst-8": (0.200000000000, 3.200000000000, 3.190268645286,
                       -3.101846256861),
            "syst-9": (0.225000000000, 3.600000000000, 3.517416263407,
                       -2.841371075544),
            "syst-10": (0.250000000000, 4.000000000000, 3.839370814447,
                        -2.592284710937),
            "syst-11": (0.275000000000, 4.400000000000, 4.165158556909,
                        -2.340284012237),
            "syst-12": (0.300000000000, 4.800000000000, 4.506345584831,
                        -2.066225859687),
            "syst-13": (0.325000000000, 5.200000000000, 4.879529007461,
                        -1.739297079458),
            "syst-14": (0.350000000000, 5.600000000000, 5.310823513733,
                        -1.301816690532),
            "syst-15": (0.375000000000, 6.000000000000, 5.838779417089,
                        -0.646704214263),
            "rand-1": (0.021228232647, 5.868452651315, 5.859729688192,
                       -0.432264760951),
            "rand-2": (0.016968378871, 4.761021655110, 4.744061786583,
                       -1.556088761716),
            "rand-3": (0.018578311703, 2.464435046216, 2.475908955821,
                       2.487300499232),
            "rand-4": (0.016386947254, 1.075597681642, 1.090127758250,
                       1.104713814823),
            "rand-5": (0.017651152200, 0.200011672644, 0.203580329847,
                       0.207180380010),
            "rand-6": (0.006923074624, 0.290103403226, 0.292096978801,
                       0.294097208267),
            "rand-7": (0.002428294531, 5.173938128028, 5.171761572640,
                       -1.113601464490),
            "rand-8": (0.017370715574, 1.992394794033, 2.008130645020,
                       2.023809681520),
            "rand-9": (0.023755551221, 0.216431106906, 0.221653600172,
                       0.226938058952),
            "rand-10": (0.010968608991, 2.397402491437, 2.404772696274,
                        2.412113273400),
            "rand-11": (0.019137919704, 4.996388335095, 4.977921138154,
                        -1.323779018431),
            "rand-12": (0.004671815114, 3.077280455596, 3.077579312617,
                        3.077877470783),
            "rand-13": (0.011139655018, 4.060904408970, 4.052106100441,
                        -2.239847775747),
            "rand-14": (0.017734120771, 4.741836271756, 4.724103367769,
                        -1.576817615338),
            "rand-15": (0.006900626925, 4.270697872458, 4.264477964900,
                        -2.024918020450),
            "rand-16": (0.016377450099, 1.021719665350, 1.035808775845,
                        1.049957669774),
            "rand-17": (0.002974942039, 3.131313689041, 3.131344177237,
                        3.131374620007),
            "rand-18": (0.023993598963, 2.138706596562, 2.158672164638,
                        2.178507958606),
            "rand-19": (0.014631693774, 1.406251889782, 1.420719116738,
                        1.435202708137),
            "rand-20": (0.018781676483, 1.602809881387, 1.621567356335,
                        1.640316999728),
        }

        for (_, value) in tabulation.iteritems():
            (ref_eccentricity, ref_mean_anomaly, ref_ecc_anomaly,
             _ref_true_anomaly) = value
            exo_ecc_anomaly = eccanom(ref_mean_anomaly, ref_eccentricity)
            # 1: ensure the output agrees with the tabulation
            self.assertAlmostEqual(exo_ecc_anomaly,
                                   ref_ecc_anomaly,
                                   delta=1e-6)
            # 2: additionally, ensure the Kepler relation:
            #   M = E - e sin E
            # is satisfied for the output of eccanom().
            # Here, e is the given eccentricity, E is the EXOSIMS eccentric
            # anomaly, and M is the mean anomaly.
            est_mean_anomaly = exo_ecc_anomaly - ref_eccentricity * np.sin(
                exo_ecc_anomaly)
            self.assertAlmostEqual(ref_mean_anomaly,
                                   est_mean_anomaly,
                                   delta=1e-6)
コード例 #14
0
    def keplerplanet(self, currentTime, bodyname, eclip=False):
        """Finds solar system body positions vector in heliocentric equatorial (default)
        or ecliptic frame for current time (MJD).
        
        This method uses algorithms 2 and 10 from Vallado 2013 to find 
        heliocentric equatorial position vectors for solar system objects.
        
        Args:
            currentTime (astropy Time array):
                Current absolute mission time in MJD
            bodyname (string):
                Solar system object name
            eclip (boolean):
                Boolean used to switch to heliocentric ecliptic frame. Defaults to 
                False, corresponding to heliocentric equatorial frame.
        
        Returns:
            r_body (astropy Quantity nx3 array):
                Solar system body positions in heliocentric equatorial (default)
                or ecliptic frame in units of AU
        
        Note: Use eclip=True to get ecliptic coordinates.
        
        """

        # Moon positions based on Earth positions
        if bodyname == 'Moon':
            r_Earth = self.keplerplanet(currentTime, 'Earth')
            return r_Earth + self.moon_earth(currentTime)

        assert self.planets.has_key(bodyname),\
                "%s is not a recognized body name."%(bodyname)

        # find Julian centuries from J2000
        TDB = self.cent(currentTime)
        # update ephemerides data (convert sma from km to AU)
        planet = self.planets[bodyname]
        a = (self.propeph(planet.a, TDB) * u.km).to('AU').value
        e = self.propeph(planet.e, TDB)
        I = np.radians(self.propeph(planet.I, TDB))
        O = np.radians(self.propeph(planet.O, TDB))
        w = np.radians(self.propeph(planet.w, TDB))
        lM = np.radians(self.propeph(planet.lM, TDB))
        # find mean anomaly and argument of perigee
        M = (lM - w) % (2 * np.pi)
        wp = (w - O) % (2 * np.pi)
        # find eccentric anomaly
        E = eccanom(M, e)[0]
        # find true anomaly
        nu = np.arctan2(np.sin(E) * np.sqrt(1 - e**2), np.cos(E) - e)
        # find semiparameter
        p = a * (1 - e**2)
        # body positions vector in orbital plane
        rx = p * np.cos(nu) / (1 + e * np.cos(nu))
        ry = p * np.sin(nu) / (1 + e * np.cos(nu))
        rz = np.zeros(currentTime.size)
        r_orb = np.array([rx, ry, rz])
        # body positions vector in heliocentric ecliptic plane
        r_body = np.array([
            np.dot(np.dot(self.rot(-O[x], 3), self.rot(-I[x], 1)),
                   np.dot(self.rot(-wp[x], 3), r_orb[:, x]))
            for x in range(currentTime.size)
        ]) * u.AU

        if not eclip:
            # body positions vector in heliocentric equatorial frame
            r_body = self.eclip2equat(r_body, currentTime)

        return r_body
コード例 #15
0
    def gen_update(self, TL):
        """Generates dynamic completeness values for multiple visits of each 
        star in the target list
        
        Args:
            TL (TargetList):
                TargetList class object
        
        """
        
        OS = TL.OpticalSystem
        PPop = TL.PlanetPopulation
        
        # limiting planet delta magnitude for completeness
        dMagMax = self.dMagLim
        
        # get name for stored dynamic completeness updates array
        # inner and outer working angles for detection mode
        mode = list(filter(lambda mode: mode['detectionMode'] == True, OS.observingModes))[0]
        IWA = mode['IWA']
        OWA = mode['OWA']
        extstr = self.extstr + 'IWA: ' + str(IWA) + ' OWA: ' + str(OWA) + \
                ' dMagMax: ' + str(dMagMax) + ' nStars: ' + str(TL.nStars)
        ext = hashlib.md5(extstr.encode('utf-8')).hexdigest()
        self.dfilename += ext 
        self.dfilename += '.dcomp'

        path = os.path.join(self.cachedir, self.dfilename)
        # if the 2D completeness update array exists as a .dcomp file load it
        if os.path.exists(path):
            self.vprint('Loading cached dynamic completeness array from "%s".' % path)
            try:
                with open(path, "rb") as ff:
                    self.updates = pickle.load(ff)
            except UnicodeDecodeError:
                with open(path, "rb") as ff:
                    self.updates = pickle.load(ff,encoding='latin1')
            self.vprint('Dynamic completeness array loaded from cache.')
        else:
            # run Monte Carlo simulation and pickle the resulting array
            self.vprint('Cached dynamic completeness array not found at "%s".' % path)
            self.vprint('Beginning dynamic completeness calculations')
            # dynamic completeness values: rows are stars, columns are number of visits
            self.updates = np.zeros((TL.nStars, 5))
            # number of planets to simulate
            nplan = int(2e4)
            # sample quantities which do not change in time
            a, e, p, Rp = PPop.gen_plan_params(nplan)
            a = a.to('AU').value
            # sample angles
            I, O, w = PPop.gen_angles(nplan)
            I = I.to('rad').value
            O = O.to('rad').value
            w = w.to('rad').value
            Mp = PPop.gen_mass(nplan) # M_earth
            rmax = a*(1.+e) # AU
            # sample quantity which will be updated
            M = np.random.uniform(high=2.*np.pi,size=nplan)
            newM = np.zeros((nplan,))
            # population values
            smin = (np.tan(IWA)*TL.dist).to('AU').value
            if np.isfinite(OWA):
                smax = (np.tan(OWA)*TL.dist).to('AU').value
            else:
                smax = np.array([np.max(PPop.arange.to('AU').value)*\
                        (1.+np.max(PPop.erange))]*TL.nStars)
            # fill dynamic completeness values
            for sInd in xrange(TL.nStars):
                mu = (const.G*(Mp + TL.MsTrue[sInd])).to('AU3/day2').value
                n = np.sqrt(mu/a**3) # in 1/day
                # normalization time equation from Brown 2015
                dt = 58.0*(TL.L[sInd]/0.83)**(3.0/4.0)*(TL.MsTrue[sInd]/(0.91*u.M_sun))**(1.0/2.0) # days
                # remove rmax < smin 
                pInds = np.where(rmax > smin[sInd])[0]
                # calculate for 5 successive observations
                for num in xrange(5):
                    if num == 0:
                        self.updates[sInd, num] = TL.comp0[sInd]
                    if not pInds.any():
                        break
                    # find Eccentric anomaly
                    if num == 0:
                        E = eccanom(M[pInds],e[pInds])
                        newM[pInds] = M[pInds]
                    else:
                        E = eccanom(newM[pInds],e[pInds])
                    
                    r1 = a[pInds]*(np.cos(E) - e[pInds])
                    r1 = np.hstack((r1.reshape(len(r1),1), r1.reshape(len(r1),1), r1.reshape(len(r1),1)))
                    r2 = (a[pInds]*np.sin(E)*np.sqrt(1. -  e[pInds]**2))
                    r2 = np.hstack((r2.reshape(len(r2),1), r2.reshape(len(r2),1), r2.reshape(len(r2),1)))
                    
                    a1 = np.cos(O[pInds])*np.cos(w[pInds]) - np.sin(O[pInds])*np.sin(w[pInds])*np.cos(I[pInds])
                    a2 = np.sin(O[pInds])*np.cos(w[pInds]) + np.cos(O[pInds])*np.sin(w[pInds])*np.cos(I[pInds])
                    a3 = np.sin(w[pInds])*np.sin(I[pInds])
                    A = np.hstack((a1.reshape(len(a1),1), a2.reshape(len(a2),1), a3.reshape(len(a3),1)))
                    
                    b1 = -np.cos(O[pInds])*np.sin(w[pInds]) - np.sin(O[pInds])*np.cos(w[pInds])*np.cos(I[pInds])
                    b2 = -np.sin(O[pInds])*np.sin(w[pInds]) + np.cos(O[pInds])*np.cos(w[pInds])*np.cos(I[pInds])
                    b3 = np.cos(w[pInds])*np.sin(I[pInds])
                    B = np.hstack((b1.reshape(len(b1),1), b2.reshape(len(b2),1), b3.reshape(len(b3),1)))
                    
                    # planet position, planet-star distance, apparent separation
                    r = (A*r1 + B*r2) # position vector (AU)
                    d = np.linalg.norm(r,axis=1) # planet-star distance
                    s = np.linalg.norm(r[:,0:2],axis=1) # apparent separation
                    beta = np.arccos(r[:,2]/d) # phase angle
                    Phi = self.PlanetPhysicalModel.calc_Phi(beta*u.rad) # phase function
                    dMag = deltaMag(p[pInds],Rp[pInds],d*u.AU,Phi) # difference in magnitude
                    
                    toremoves = np.where((s > smin[sInd]) & (s < smax[sInd]))[0]
                    toremovedmag = np.where(dMag < dMagMax)[0]
                    toremove = np.intersect1d(toremoves, toremovedmag)
                    
                    pInds = np.delete(pInds, toremove)
                    
                    if num == 0:
                        self.updates[sInd, num] = TL.comp0[sInd]
                    else:
                        self.updates[sInd, num] = float(len(toremove))/nplan
                    
                    # update M
                    newM[pInds] = (newM[pInds] + n[pInds]*dt)/(2*np.pi) % 1 * 2.*np.pi
                    
                if (sInd+1) % 50 == 0:
                    self.vprint('stars: %r / %r' % (sInd+1,TL.nStars))
            # ensure that completeness values are between 0 and 1
            self.updates = np.clip(self.updates, 0., 1.)
            # store dynamic completeness array as .dcomp file
            with open(path, 'wb') as ff:
                pickle.dump(self.updates, ff)
            self.vprint('Dynamic completeness calculations finished')
            self.vprint('Dynamic completeness array stored in %r' % path)
コード例 #16
0
Bmag = 5.66  #(mag)
radius = 1.23  #r sun
star_d = 13.802083302115193  #distance (pc) ±0.028708172014593
star_mass = 1.03  #0.05

#### Randomly Generate 47 UMa c planet parameters
n = 10**5
inc, W, w = PPop.gen_angles(n, None)
inc = inc.to('rad').value
inc[np.where(inc > np.pi / 2)[0]] = np.pi - inc[np.where(inc > np.pi / 2)[0]]
W = W.to('rad').value
w = w.to('rad').value
a, e, p, Rp = PPop.gen_plan_params(n)
a = a.to('AU').value
M0 = rand.uniform(low=0., high=2 * np.pi, size=n)  #rand.random(360, size=n)
E = eccanom(M0, e)  # eccentric anomaly

a = rand.uniform(low=3.5, high=3.7,
                 size=n) * u.AU  # (3.7-3.5)*rand.random(n)+3.5 #uniform random
e = rand.uniform(low=0.002, high=0.145,
                 size=n)  #(0.145-0.002)*rand.random(n)+0.02 #uniform random
Msini = rand.uniform(low=0.467, high=0.606,
                     size=n)  #(0.606-0.467)*rand.random(n)+0.467
Mp = (Msini / np.sin(inc) * u.M_jup).to('M_earth')
#TODO CHECK FOR INF/TOO LARGE
print('Done Generating planets 1')

Rp = PPM.calc_radius_from_mass(Mp)
indsTooBig = np.where(
    Rp < 12 *
    u.earthRad)[0]  #throws out planets with radius 12x larger than Earth
コード例 #17
0
    def keplerplanet(self, currentTime, bodyname):
        """Finds position vector for solar system objects
        
        This method uses algorithms 2 and 10 from Vallado 2013 to find 
        heliocentric equatorial position vectors (astropy Quantity in km) for 
        solar system objects.
        
        Args:
            currentTime (astropy Time):
                Current absolute mission time in MJD
            bodyname (string):
                Solar system object name
        
        Returns:
            r_body (astropy Quantity nx3 array):
                Heliocentric equatorial position vector in units of km
        
        """

        # reshape currentTime
        currentTime = currentTime.reshape(currentTime.size)

        if bodyname == 'Moon':
            r_Earth = self.keplerplanet(currentTime, 'Earth')
            return r_Earth + self.moon_earth(currentTime)

        assert self.planets.has_key(bodyname),\
                "%s is not a recognized body name."%(bodyname)

        planet = self.planets[bodyname]
        # find Julian centuries from J2000
        TDB = self.cent(currentTime)
        # update ephemeride data
        a = self.propeph(planet.a, TDB)
        e = self.propeph(planet.e, TDB)
        I = np.radians(self.propeph(planet.I, TDB))
        O = np.radians(self.propeph(planet.O, TDB))
        w = np.radians(self.propeph(planet.w, TDB))
        lM = np.radians(self.propeph(planet.lM, TDB))
        # Find mean anomaly and argument of perigee
        M = np.mod(lM - w, 2 * np.pi)
        wp = np.mod(w - O, 2 * np.pi)
        # Find eccentric anomaly
        E = eccanom(M, e)[0]
        # Find true anomaly
        nu = np.arctan2(np.sin(E) * np.sqrt(1 - e**2), np.cos(E) - e)
        # Find semiparameter
        p = a * (1 - e**2)
        # position vector (km) in orbital plane
        rx = p * np.cos(nu) / (1 + e * np.cos(nu))
        ry = p * np.sin(nu) / (1 + e * np.cos(nu))
        rz = np.zeros(currentTime.size)
        r_body = np.vstack((rx, ry, rz)).T
        # position vector (km) in ecliptic plane
        r_body = np.array([np.dot(np.dot(self.rot(-O[x],3),self.rot(-I[x],1)),\
                np.dot(self.rot(-wp[x],3),r_body[x,:])) for x in range(currentTime.size)])
        # find obliquity of the ecliptic
        obe = np.radians(self.obe(TDB))
        # position vector (km) in heliocentric equatorial frame
        r_body = np.array([np.dot(self.rot(-obe[x],1),r_body[x,:])\
                for x in range(currentTime.size)])*u.km

        return r_body.to('km').reshape(currentTime.size, 3)