Example #1
0
    def test_init_ipac_compare(self):
        r"""Test of initialization and __init__ -- compare values to independently-extracted values.

        Method: Loop over the extracted values from EXOSIMS, and find the corresponding
        planet in the online catalog, as loaded in the first lines in this code.
        Compare values for all important parameters.  The values used by subsequent code
        are (from SimulatedUniverse/KnownRVPlanetsUniverse):
        *  (sma, smaerr) = semi-major axis & error
        *  (eccen, eccenerr) = eccentricity & error
        also present here:
           plan_pop.hostname (string)
        and, as well,
           plan_pop.allplanetdata[pl_orbitincl] = orbital inclination
        *  plan_pop.mass = mass of planet
           plan_pop.allplanetdata['pl_orblper'] = longitude of periapsis
        We check the starred values.
        """

        plan_pop = self.fixture
        # ensure basic module attributes are set up
        self.validate_planet_population(plan_pop)

        # Load canned RV planet information
        # d_ref is a dictionary, indexed by (stellar) host name,
        # containing lists of dictionaries of planet attributes.  For instance:
        #   d_ref['HD 12661']
        # contains a list of two entries (two planets), and
        #   d_ref['HD 12661'][0]['pl_orbeccen']
        # is a floating-point eccentricity for the first planet, or None if the
        # eccentricity is not known.
        comparison_file = os.path.join(resource_path(),
                                       'ipac-rv-data-planets.csv')
        d_ref = load_vo_csvfile(comparison_file, exoplanet_unit_map)
        # d_ref = load_rv_planet_comparison()

        # loop over all RV planets, looking for matches
        hosts_not_matched = 0
        for n_planet in range(len(plan_pop.hostname)):
            # specific "plan_pop" information we will check for this planet
            host_1 = plan_pop.hostname[n_planet]
            sma_1 = plan_pop.sma[n_planet]
            sma_err_1 = plan_pop.smaerr[n_planet]
            ecc_1 = plan_pop.eccen[n_planet]
            ecc_err_1 = plan_pop.eccenerr[n_planet]
            mass_1 = plan_pop.mass[n_planet]
            # reference information:
            # it's a list, because there could be several planets around that host
            self.assertIn(host_1, d_ref)
            info_refs = d_ref[host_1]
            # pick out the right planet using agreement of SMA
            info_ref = [
                d for d in info_refs
                if (d['pl_orbsmax'] is not None
                    and np.abs(d['pl_orbsmax'] - sma_1).to(u.au).value < 1e-3)
            ]
            # zero matches is possible, because plan_pop.__init__ fills in a few
            # SMA values on its own if a planet is detected but SMA is not recorded by IPAC.
            if len(info_ref) != 1:
                hosts_not_matched += 1  # count them: we don't allow too many unmatched planets
                continue
            # assert that there was not a double-match -- should not happen
            self.assertEqual(len(info_ref),
                             1,
                             msg=('Multiple matches for ' + host_1))
            # take the (unique) matching object
            info_ref = info_ref[0]
            # check info_ref attributes (i.e., our reference values) against plan_pop
            #   note, all these checks are very tight in tolerance, because any difference
            #   should only arise due to float -> ascii -> float conversions
            # 1: check SMA, use relative error
            if info_ref['pl_orbsmax'] is not None:
                delta = ((info_ref['pl_orbsmax'] - sma_1) /
                         sma_1).decompose().value
                self.assertAlmostEqual(delta,
                                       0.0,
                                       msg=('SMA difference in %s' % host_1),
                                       delta=1e-6)
            # 2: check SMA error, use absolute error in AU
            if info_ref['pl_orbsmaxerr1'] is not None:
                # the error can be small, so no relative error
                delta = (info_ref['pl_orbsmaxerr1'] - sma_err_1).to(u.au).value
                self.assertAlmostEqual(delta,
                                       0.0,
                                       msg=('SMA_error difference in %s' %
                                            host_1),
                                       delta=1e-6)
            # 3: check eccentricity, just a float
            if info_ref['pl_orbeccen'] is not None:
                self.assertAlmostEqual(info_ref['pl_orbeccen'],
                                       ecc_1,
                                       msg=('eccentricity difference in %s' %
                                            host_1),
                                       delta=1e-6)
            # 4: check eccentricity error, also a float
            if info_ref['pl_orbeccenerr1'] is not None:
                self.assertAlmostEqual(info_ref['pl_orbeccenerr1'],
                                       ecc_err_1,
                                       msg=('eccen_error difference in %s' %
                                            host_1),
                                       delta=1e-6)
            # 5: check mass, use relative error
            if info_ref['pl_bmasse'] is not None:
                delta = ((info_ref['pl_bmasse'] - mass_1) /
                         mass_1).decompose().value
                self.assertAlmostEqual(delta,
                                       0.0,
                                       msg=('Mass difference in %s' % host_1),
                                       delta=1e-6)
        # ensure there are not too many un-matched host stars
        self.assertLess(
            hosts_not_matched,
            len(plan_pop.hostname) // 10,
            'Too many stars in PlanetPopulation are unmatched in the catalog.')
Example #2
0
    def test_init_stellar_attributes(self):
        r"""Test of initialization and __init__ -- stellar attributes.

        Method: Comprehensive check of all target-star stored attributes
        against tabulated values, for all stars.
        TODO: Numerical checks on comp0 attribute
        """
        tlist = self.fixture
        self.basic_validation(tlist)
        # Load canned RV exo-star information
        # d_ref is a dictionary, indexed by (stellar) host name,
        # containing lists of dictionaries of star attributes.  For instance:
        #   d_ref['HD 12661']
        # contains a list of two entries (two planets for that star), and
        #   d_ref['HD 12661'][0]['st_plx']
        # is a floating-point parallax for the first planet, or None if the
        # parallax is not known.
        # Because we're checking stellar properties here, the list entries
        # refer to the same host star, so index [0] is the same as index [1],
        # etc.
        comparison_file = os.path.join(resource_path(), 'ipac-rv-data-stars.csv')
        d_ref = load_vo_csvfile(comparison_file, exostar_unit_map)
        # loop over all RV host stars, looking for matching stars in the file
        hosts_not_matched = 0
        for n_host in range(len(tlist.Name)):
            # check information for the following host
            host = tlist.Name[n_host]
            if host not in d_ref:
                hosts_not_matched += 1
                continue
            # check all the attributes created in the tlist's __init__
            # the "atts_mapping" dictionary maps:
            #    tlist attribute names => votable attribute names
            for (name_att, name_vo) in tlist.atts_mapping.items():
                # the EXOSIMS value: tlist.$name_e[n_host]
                val_e = getattr(tlist, name_att)[n_host]
                # the validation value
                val_v = d_ref[host][0][name_vo]
                # if missing data in the validation table, skip -- it's a NaN
                if val_v is None:
                    continue
                assert isinstance(val_e, u.quantity.Quantity) == isinstance(val_v, u.quantity.Quantity), \
                    'Units mismatch in key %s, check atts_mapping dictionary in test code.' % name_att
                if isinstance(val_e, u.quantity.Quantity):
                    val_e = val_e.value
                    val_v = val_v.value
                # otherwise, check it
                self.assertEqual(val_e, val_v,
                                 msg=('Difference in star "%s", attribute "%s": %s vs. %s' %
                                      (host, name_att, val_e, val_v)))
            # check ra, dec, which are handled separately
            for name_att in ['ra', 'dec']:
                # the EXOSIMS value
                val_e  = getattr(tlist.coords[n_host], name_att)
                # the validation value
                val_v = d_ref[host][0][name_att]
                # allow a small difference in case of truncation issues
                self.assertAlmostEqual(val_e.to(u.deg).value, val_v.to(u.deg).value,
                                msg=('Difference in star "%s", attribute "%s": %s vs. %s' %
                                (host, name_att, val_e, val_v)), delta=1e-4)
            # optionally:
            # check tlist.maxintTime, tlist.comp0
            # noted: tlist.Binary_Cut seems not based in measurements
        # ensure there are not too many un-matched host stars
        self.assertLess(hosts_not_matched, len(tlist.Name)//10,
                        'Too many stars in TargetList are unmatched in the catalog.')
    def test_init_ipac_compare(self):
        r"""Test of initialization and __init__ -- compare values to independently-extracted values.

        Method: Loop over the extracted values from EXOSIMS, and find the corresponding
        planet in the online catalog, as loaded in the first lines in this code.
        Compare values for all important parameters.  The values used by subsequent code
        are (from SimulatedUniverse/KnownRVPlanetsUniverse):
        *  (sma, smaerr) = semi-major axis & error
        *  (eccen, eccenerr) = eccentricity & error
        also present here:
           plan_pop.hostname (string)
        and, as well,
           plan_pop.allplanetdata[pl_orbitincl] = orbital inclination
        *  plan_pop.mass = mass of planet
           plan_pop.allplanetdata['pl_orblper'] = longitude of periapsis
        We check the starred values.
        """

        plan_pop = self.fixture
        # ensure basic module attributes are set up
        self.validate_planet_population(plan_pop)

        # Load canned RV planet information
        # d_ref is a dictionary, indexed by (stellar) host name,
        # containing lists of dictionaries of planet attributes.  For instance:
        #   d_ref['HD 12661']
        # contains a list of two entries (two planets), and
        #   d_ref['HD 12661'][0]['pl_orbeccen']
        # is a floating-point eccentricity for the first planet, or None if the
        # eccentricity is not known.
        comparison_file = os.path.join(resource_path(), 'ipac-rv-data-planets.csv')
        d_ref = load_vo_csvfile(comparison_file, exoplanet_unit_map)
        # d_ref = load_rv_planet_comparison()

        # loop over all RV planets, looking for matches
        hosts_not_matched = 0
        for n_planet in range(len(plan_pop.hostname)):
            # specific "plan_pop" information we will check for this planet
            host_1    = plan_pop.hostname[n_planet]
            sma_1     = plan_pop.sma[n_planet]
            sma_err_1 = plan_pop.smaerr[n_planet]
            ecc_1     = plan_pop.eccen[n_planet]
            ecc_err_1 = plan_pop.eccenerr[n_planet]
            mass_1    = plan_pop.mass[n_planet]
            # reference information:
            # it's a list, because there could be several planets around that host
            self.assertIn(host_1, d_ref)
            info_refs = d_ref[host_1]
            # pick out the right planet using agreement of SMA
            info_ref = [d for d in info_refs if (d['pl_orbsmax'] is not None
                                                 and
                                                 np.abs(d['pl_orbsmax'] - sma_1).to(u.au).value < 1e-3)]
            # zero matches is possible, because plan_pop.__init__ fills in a few
            # SMA values on its own if a planet is detected but SMA is not recorded by IPAC.
            if len(info_ref) != 1:
                hosts_not_matched += 1 # count them: we don't allow too many unmatched planets
                continue
            # assert that there was not a double-match -- should not happen
            self.assertEqual(len(info_ref), 1, msg=('Multiple matches for ' + host_1))
            # take the (unique) matching object
            info_ref = info_ref[0]
            # check info_ref attributes (i.e., our reference values) against plan_pop
            #   note, all these checks are very tight in tolerance, because any difference
            #   should only arise due to float -> ascii -> float conversions
            # 1: check SMA, use relative error
            if info_ref['pl_orbsmax'] is not None:
                delta = ((info_ref['pl_orbsmax'] - sma_1)/sma_1).decompose().value
                self.assertAlmostEqual(delta, 0.0, msg=('SMA difference in %s' % host_1), delta=1e-6)
            # 2: check SMA error, use absolute error in AU
            if info_ref['pl_orbsmaxerr1'] is not None:
                # the error can be small, so no relative error
                delta = (info_ref['pl_orbsmaxerr1'] - sma_err_1).to(u.au).value
                self.assertAlmostEqual(delta, 0.0, msg=('SMA_error difference in %s' % host_1), delta=1e-6)
            # 3: check eccentricity, just a float
            if info_ref['pl_orbeccen'] is not None:
                self.assertAlmostEqual(info_ref['pl_orbeccen'], ecc_1,
                                       msg=('eccentricity difference in %s' % host_1), delta=1e-6)
            # 4: check eccentricity error, also a float
            if info_ref['pl_orbeccenerr1'] is not None:
                self.assertAlmostEqual(info_ref['pl_orbeccenerr1'], ecc_err_1,
                                       msg=('eccen_error difference in %s' % host_1), delta=1e-6)
            # 5: check mass, use relative error
            if info_ref['pl_bmasse'] is not None:
                delta = ((info_ref['pl_bmasse'] - mass_1)/mass_1).decompose().value
                self.assertAlmostEqual(delta, 0.0, msg=('Mass difference in %s' % host_1), delta=1e-6)
        # ensure there are not too many un-matched host stars
        self.assertLess(hosts_not_matched, len(plan_pop.hostname)//10,
                        'Too many stars in PlanetPopulation are unmatched in the catalog.')