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.')
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.')