Esempio n. 1
0
    def calculate_uncertainties(self):
        """
        Calculate the uncertainties of this parameter.
        """

        # If this parameter does not allow uncertainties, set them to None.
        if not self.uncertain_flag:
            self.uncertainty = None
            self.uncertainty_lower = None
            self.uncertainty_upper = None
            return

        # If all uncertainties are empty, reset them to uncertainties provided
        # by the initial template construction.
        elif (is_empty(self.uncertainty) and
              is_empty(self.uncertainty_lower) and
              is_empty(self.uncertainty_upper)
              ):
            self.reset_uncertainties()
            return

        # If upper and lower uncertainties are provided, calculate the mean
        # uncertainty.
        elif (is_valid(self.uncertainty_lower)
              and is_valid(self.uncertainty_upper)
              ):
            u_hi = Decimal(self.uncertainty_upper)
            u_lo = Decimal(self.uncertainty_lower)
            u_avg = (u_lo + u_hi) / 2
            self.uncertainty = Decimal(u_avg)

        # If mean and upper uncertainties are provided, calculate ther lower
        # uncertainty.
        elif (is_valid(self.uncertainty) and is_valid(self.uncertainty_upper)):
            u_hi = Decimal(self.uncertainty_upper)
            u_avg = Decimal(self.uncertainty)
            u_lo = (2 * u_avg) - u_hi
            self.uncertainty_lower = Decimal(u_lo)

        # If only an upper uncertainty is provided, treat this as the mean.
        elif (is_empty(self.uncertainty) and is_valid(self.uncertainty_upper)):
            temp = Decimal(self.uncertainty_upper)
            self.reset_uncertainties()
            self.uncertainty = temp

        # If only a lower uncertainty is provided, treat this as the mean.
        elif (is_empty(self.uncertainty) and is_valid(self.uncertainty_lower)):
            temp = Decimal(self.uncertainty_lower)
            self.reset_uncertainties()
            self.uncertainty = temp

        else:
            return
Esempio n. 2
0
    def calculate_uncertainties(self):
        """
        Calculate the uncertainties of this parameter.
        """

        # If this parameter does not allow uncertainties, set them to None.
        if not self.uncertain_flag:
            self.uncertainty = None
            self.uncertainty_lower = None
            self.uncertainty_upper = None
            return

        # If all uncertainties are empty, reset them to uncertainties provided
        # by the initial template construction.
        elif (is_empty(self.uncertainty) and is_empty(self.uncertainty_lower)
              and is_empty(self.uncertainty_upper)):
            self.reset_uncertainties()
            return

        # If upper and lower uncertainties are provided, calculate the mean
        # uncertainty.
        elif (is_valid(self.uncertainty_lower)
              and is_valid(self.uncertainty_upper)):
            u_hi = Decimal(self.uncertainty_upper)
            u_lo = Decimal(self.uncertainty_lower)
            u_avg = (u_lo + u_hi) / 2
            self.uncertainty = Decimal(u_avg)

        # If mean and upper uncertainties are provided, calculate ther lower
        # uncertainty.
        elif (is_valid(self.uncertainty) and is_valid(self.uncertainty_upper)):
            u_hi = Decimal(self.uncertainty_upper)
            u_avg = Decimal(self.uncertainty)
            u_lo = (2 * u_avg) - u_hi
            self.uncertainty_lower = Decimal(u_lo)

        # If only an upper uncertainty is provided, treat this as the mean.
        elif (is_empty(self.uncertainty) and is_valid(self.uncertainty_upper)):
            temp = Decimal(self.uncertainty_upper)
            self.reset_uncertainties()
            self.uncertainty = temp

        # If only a lower uncertainty is provided, treat this as the mean.
        elif (is_empty(self.uncertainty) and is_valid(self.uncertainty_lower)):
            temp = Decimal(self.uncertainty_lower)
            self.reset_uncertainties()
            self.uncertainty = temp

        else:
            return
Esempio n. 3
0
    def _calculate_rhostar(self):
        """
        If needed, calculate RHOSTAR using MSTAR and RSTAR if available.
        """

        if (is_empty(self.rhostar.value)
            and is_valid(self.mstar.value)
            and is_valid(self.rstar.value)
            ):

            mstar = Decimal(self.mstar.value)
            rstar = Decimal(self.rstar.value)
            density = (mstar * (Decimal(1.41) / (rstar ** 3)))

            mu = Decimal(self.mstar.uncertainty)
            ru = Decimal(self.rstar.uncertainty)
            if is_valid(mu) and is_valid(ru):
                du = (mu * (Decimal(1.41) / (ru ** 3)))
            else:
                du = 'NaN'

            self.rhostar.value = round(density, len(str(mstar)))
            self.rhostar.uncertainty = du
            self.rhostar.reference = "Calculated from MSTAR and RSTAR"
            self.rhostar.url = str(self.mstar.url)
Esempio n. 4
0
    def set_from_dict(self, attribute_dict):
        """
        Update the attributes of this ExoParameter using a provided dictionary.

        :param attribute_dict:  This module needs a dictionary of attribute /
                                value pairs to set attributes of self.
        :type attribute_dict:  dict
        """

        # Iterate through each attribute / value pair in the dictionary.
        for attr, value in attribute_dict.items():

            # Get the value currently in self.attr.  Use None if this is not a
            # current attribute of self.
            try:
                old_value = getattr(self, attr)
            except AttributeError:
                old_value = None

            # Uncertainty values from the GUI will either be None or Decimals.
            # We want to prevent overwriting "NaN" with None.
            if (value is None and is_empty(old_value)):
                continue

            # Update self.
            setattr(self, attr, value)

        # If no value is provided, set to default.
        if self.value is None:
            self.value = self.default
Esempio n. 5
0
    def _add_nasa_value(self, frame, attr):
        """
        Add values from a CustomNASA object to an ExoPlanet object.

        :param frame:  The ingested NASA Archive .csv file.
        :type frame:  CustomNASA

        :param attr:  The ExoPlanet attribute to be updated.
        :type attr:  ExoParameter
        """

        # Look up the appropriate field to look for in the CustomNASA object.
        # If nasa_field is empty, return immediately.
        nasa_str = attr.nasa_field
        if is_empty(nasa_str):
            return

        # Get the current ExoParameter attached to attr, and update the
        # new value.
        attr.value = frame.read_val(nasa_str)
        if is_valid(attr.value):
            print("Updated {0} for {1}".format(attr.parameter,
                                               self.name.value
                                               ))

        # Update error values for this attribute.
        hi, lo = frame.read_errors(nasa_str)
        attr.uncertainty_upper = hi
        attr.uncertainty_lower = lo

        # Get the reference and url strings for this attribute.
        attr.reference, attr.url = frame.read_refs()
Esempio n. 6
0
    def set_from_dict(self, attribute_dict):
        """
        Update the attributes of this ExoParameter using a provided dictionary.

        :param attribute_dict:  This module needs a dictionary of attribute /
                                value pairs to set attributes of self.
        :type attribute_dict:  dict
        """

        # Iterate through each attribute / value pair in the dictionary.
        for attr, value in attribute_dict.items():

            # Get the value currently in self.attr.  Use None if this is not a
            # current attribute of self.
            try:
                old_value = getattr(self, attr)
            except AttributeError:
                old_value = None

            # Uncertainty values from the GUI will either be None or Decimals.
            # We want to prevent overwriting "NaN" with None.
            if (value is None and is_empty(old_value)):
                continue

            # Update self.
            setattr(self, attr, value)

        # If no value is provided, set to default.
        if self.value is None:
            self.value = self.default
Esempio n. 7
0
    def _check_ar(self):
        """
        If the AR value is empty, clear the reference & url parameters.
        """

        if is_empty(self.ar.value):
            self.ar.reference = "Calculated"
            self.ar.url = None
Esempio n. 8
0
    def check_constrained(self, limit=None):
        """
        Set the well-constrained flag based on relative uncertainty percent.

        :param limit:  Optionally provide a different acceptable limit
                       tolerance (0.1 by default).
        :type limit:  float
        """

        # Set the 'well-constrained' limit at 10% (arbitrary) if not provided.
        limit = (Decimal(0.1) if not limit else Decimal(limit))

        if is_empty(self.value) or is_empty(self.uncertainty):
            return False
        elif self.uncertainty > (Decimal(self.value) * Decimal(limit)):
            self.well_constrained = False
        else:
            self.well_constrained = True
Esempio n. 9
0
    def check_constrained(self, limit=None):
        """
        Set the well-constrained flag based on relative uncertainty percent.

        :param limit:  Optionally provide a different acceptable limit
                       tolerance (0.1 by default).
        :type limit:  float
        """

        # Set the 'well-constrained' limit at 10% (arbitrary) if not provided.
        limit = (Decimal(0.1) if not limit else Decimal(limit))

        if is_empty(self.value) or is_empty(self.uncertainty):
            return False
        elif self.uncertainty > (Decimal(self.value) * Decimal(limit)):
            self.well_constrained = False
        else:
            self.well_constrained = True
Esempio n. 10
0
    def _add_simbad_coords(self, query):
        """
        Add RA and Dec information from a Simbad query to an ExoPlanet object.

        :param query:  The Simbad query object.
        :type query:  CustomSimbad
        """

        # Get the coordinate values from the query object.
        ra, dec = query.get_coordinates()

        # If either coordinate is empty, exit the function.
        if is_empty(ra) or is_empty(dec):
            pl = self.name.value
            print("Could not find Simbad coordinates for {0}".format(pl))
            return

        # Set the ExoPlanet coordinate string values to these figures.
        self.ra_string.value = str(ra)
        self.dec_string.value = str(dec)

        # Use astropy SkyCoord to convert these into coordinates in hours and
        # degrees.
        coord = SkyCoord(" ".join([ra, dec]), unit=(u.hourangle, u.deg))

        # Round the numerical coordinates to a reasonable length and set the
        # ExoPlanet attributes.
        self.ra.value = round(Decimal(coord.ra.hour), 10)
        self.dec.value = round(Decimal(coord.dec.degree), 10)

        # Set the COORDREF value to 'Simbad'.
        self.coordref.value = "Simbad"

        # Convert special characters in the SIMBADNAME to HTML friendly characters.
        ident = self.simbadname.value.replace("+", "%2B")
        ident = ident.replace(" ", "+")

        # Construct the Simbad target url and update COORDURL.
        simbad_url = "http://simbad.u-strasbg.fr/simbad/sim-basic?ident="
        self.coordurl.value = "".join([simbad_url, ident])
Esempio n. 11
0
    def reset_parameter(self, force=None):
        """
        Reset this parameter to the original template attributes.

        :param force:  Set this flag to force a reset of the given parameter.
        :type force:  bool
        """

        # Set self to a new ExoParameter using the original self.template
        # dictionary.  This will reset a parameter that has a null value or
        # it can be forced to reset.
        if (is_empty(self.value) or force):
            self = ExoParameter(self.parameter,
                                attr_dict=self.template,
                                from_template=True)
            self.value = self.default
Esempio n. 12
0
    def reset_parameter(self, force=None):
        """
        Reset this parameter to the original template attributes.

        :param force:  Set this flag to force a reset of the given parameter.
        :type force:  bool
        """

        # Set self to a new ExoParameter using the original self.template
        # dictionary.  This will reset a parameter that has a null value or
        # it can be forced to reset.
        if (is_empty(self.value) or force):
            self = ExoParameter(self.parameter,
                                attr_dict=self.template,
                                from_template=True
                                )
            self.value = self.default
Esempio n. 13
0
    def check_t0(self):
        """
        If T0 is empty, try to calculate it from a couple different methods if
        either is available.
        """

        if is_empty(self.t0.value):
            if (is_valid(self.tt.value)
                        and is_valid(self.om.value)
                        and is_valid(self.ecc.value)
                    ):
                self._calculate_t0_from_tt()
            elif (is_valid(self.m0.value)
                  and is_valid(self.reftime.value)
                  and is_valid(self.per.value)
                  and self.ecc.value == Decimal(0)
                  ):
                self._calculate_t0_from_m0()
Esempio n. 14
0
    def add_nasa_info(self, nasa_frame):
        """
        Add values from a scraped NASA Archive table to self.

        :param nasa_frame:  The scraped NASA Archive data object for this
                            planet.
        :type nasa_frame:  CustomNASA
        """

        # Keep a list of ExoPlanet attributes to update with NASA data.
        fields_to_update = ["rhostar"]

        for f in fields_to_update:

            # Get the current value of this field.
            current = getattr(self, f)

            # If there is currently no value listed for this field, look for
            # one from the provided NASA data object.
            if is_empty(current.value):
                self._add_nasa_value(nasa_frame, current)
Esempio n. 15
0
    def check_limits(self):
        """
        Compare the current value attribute to any limits provided for this
        parameter.  (not currently used)
        """

        too_hi = False
        too_lo = False
        if is_empty(self.value):
            return None

        # Check for limit violations.
        if is_valid(self.limit_lower):
            too_lo = (self.value < self.limit_lower)
        if is_valid(self.limit_upper):
            too_hi = (self.value > self.limit_upper)

        # If a limit is violated, return the designated limit action.
        if too_hi or too_lo:
            return self.limit_action
        else:
            return None
Esempio n. 16
0
    def check_limits(self):
        """
        Compare the current value attribute to any limits provided for this
        parameter.  (not currently used)
        """

        too_hi = False
        too_lo = False
        if is_empty(self.value):
            return None

        # Check for limit violations.
        if is_valid(self.limit_lower):
            too_lo = (self.value < self.limit_lower)
        if is_valid(self.limit_upper):
            too_hi = (self.value > self.limit_upper)

        # If a limit is violated, return the designated limit action.
        if too_hi or too_lo:
            return self.limit_action
        else:
            return None
Esempio n. 17
0
    def read_from_nasa(self, nasa_series):
        """
        Construct an ExoPlanet from data scraped from the NASA ExoPlanet
        Archive.

        :param nasa_series:  This function expects a data pulled for a single
                             matching exoplanet.
        :type nasa_series:  pandas.Series
        """

        # Transform the Pandas Series containing NASA parameters into a dict.
        nasa_dict = nasa_series.to_dict()

        # Look for every attribute added during ExoPlanet initialization.
        for att in self.attributes:

            # getattr will return an ExoParameter object for this attribute.
            exo_param = getattr(self, att)

            # Check for a corresponding data field in the NASA data.
            nasa_field = exo_param.nasa_field
            if nasa_field is None:
                continue

            # Get the NASA value and apply some changes based on which
            # ExoParameter we are working on.
            new_value = nasa_dict[nasa_field]
            if is_empty(new_value):
                new_value = exo_param.default

            # Remove 'd', 'm', 's' from the DEC string and fill with ' '.
            elif nasa_field == "dec_str":
                new_value = new_value.replace("d", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value[:-1]

            # NASA hd_name includes the planet letter, so cut that off.
            elif nasa_field == "hd_name":
                new_value = " ".join(new_value.split(" ")[:-1])

            # NASA hip_name includes the planet letter, so cut that off.
            elif nasa_field == "hip_name":
                new_value = " ".join(new_value.split(" ")[:-1])

            # NASA provides transit depth values in percentages, we just want
            # the decimal value.
            elif nasa_field == "pl_trandep" and is_valid(new_value):
                new_value = Decimal(new_value) / 100

            # Remove 'h', 'm', 's' from the RA string and fill with ' '.
            elif nasa_field == "ra_str":
                new_value = new_value.replace("h", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value[:-1]

            # If no RV measurements are listed in NASA, we want to use -1 for
            # our NOBS.
            elif nasa_field == "st_nrvc" and new_value == "0":
                new_value = -1

            # Try changing the new value into a Decimal.
            try:
                exo_param.value = Decimal(new_value)
            except (InvalidOperation, TypeError):
                exo_param.value = new_value

            # Try looking for corresponding uncertainty values in the NASA
            # data.
            if exo_param.uncertain_flag:

                # Create the two error column fields (for + and - uncertainty).
                nasa_err1 = "".join([nasa_field, "err1"])
                nasa_err2 = "".join([nasa_field, "err2"])

                # Pull values from these columns if they exist.
                try:
                    shi = str(nasa_dict[nasa_err1])
                    exo_param.uncertainty_upper = Decimal(shi)

                    # NASA data stores lower uncertainty as a negative number.
                    slo = str(nasa_dict[nasa_err2])
                    exo_param.uncertainty_lower = Decimal(slo) * -1

                except KeyError:
                    pass

            # Reset the current ExoPlanet attribute to the now-updated
            # ExoParameter.
            setattr(self, att, exo_param)
Esempio n. 18
0
    def verify_pln(self):
        """
        Some last-second tweaks are needed for proper .pln file formatting.
        """

        warnings = []

        self._populate_uncertainties()

        # The transitref and transiturl actually end up stored in the 'transit'
        # ExoParam due to the ref and url splits.  Pull these out and set the
        # transit entries to the proper pointers.
        if self.transit.value == 1:
            if is_empty(self.transit.reference):
                self.transit.reference = "__TRANSITREF"
            if is_empty(self.transit.url):
                self.transit.url = "__TRANSITURL"

        # If the transit depth is not provided, but an Rp/R* ratio is,
        # calculate the depth value.
        if is_empty(self.depth.value) and is_valid(self.rr.value):
            self.depth.value = self.rr.value ** 2
            if isinstance(self.rr.uncertainty, Decimal):
                self.depth.uncertainty = self.rr.uncertainty * 2
            if isinstance(self.rr.uncertainty_upper, Decimal):
                self.depth.uncertainty_upper = self.rr.uncertainty_upper * 2
            self.depth.reference = "Calculated from Rp/R*"
            self.depth.url = self.rr.reference

        # If the orbital eccentricity value is 0 and a TT value is provided,
        # use the same values for T0 as well.
        if self.ecc.value == Decimal(0) and is_empty(self.om.value):
            self.om.value = Decimal(90)
            self.om.reference = "Set to 90 deg with ecc~0"
            print("set omega to 90")
            if is_valid(self.tt.value):
                print("copying TT to T0")
                self.t0.copy_values(self.tt)
        # OM may already be set to 90.
        elif self.ecc.value == 0 and self.om.value == 90:
            if str(self.tt.value) != "NaN":
                print("copying TT to T0")
                self.t0.copy_values(self.tt)

        # Set the FREEZE_ECC flag if ECC=0 and no uncertainty is provided.
        if self.ecc.value == 0 and is_empty(self.ecc.uncertainty):
            self.freeze_ecc.value = 1

        # Set the MULT flag if NCOMP is more than 1 planet.
        if self.ncomp.value > 1:
            self.mult.value = 1

        # Set the TREND flag if a DVDT value is provided.
        if not is_empty(self.dvdt.value):
            self.trend.value = 1

        # Exclude planets with period uncertainty >10%.
        self.per.check_constrained(0.1)
        if not self.per.well_constrained:
            self.exclude()
            warnings.append("<uncertain PER>")

        # Warn of planets with K speeds <2 m/s.
        if is_valid(self.k.value):
            if self.k.value < 2:
                # self.exclude()
                warnings.append("<low K value>")

        # Make sure RA string uses spaces.
        if not is_empty(self.ra_string.value):
            if "h" in self.ra_string.value:
                new_value = self.ra_string.value.replace("h", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value.replace("s", "")
                self.ra_string.value = new_value

        # Make sure DEC string uses spaces.
        if not is_empty(self.dec_string.value):
            if "d" in self.dec_string.value:
                new_value = self.dec_string.value.replace("d", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value.replace("s", "")
                self.dec_string.value = new_value

        # Display warnings generated by final adjustments.
        if len(warnings) > 0:
            print("<<<{0} GOT {1} WARNING(S)>>>".format(self.name.value,
                                                        len(warnings)
                                                        )
                  )
            [print(x) for x in warnings]
Esempio n. 19
0
    def save_to_pln(self, name=None, dir=None, pref=None, disp=True):
        """
        Save an ExoPlanet object into a .pln text file.  A .pln template is
        needed here to recreate the sections of the text file and where to
        write each parameter.

        :param name:  The file name for the resulting .pln file.  This will be
                      automatically set to the exoplanet name if not provided,
                      but the user may supply a different name for testing.
        :type name:  str

        :param gui:  Flag used to alter the filename if this file is being
                     generated by the GUI.
        :type gui:  bool
        """

        # If name is not provided, use the NAME field value + .pln.
        if not name:
            name = ".".join([self.name.value, "pln"])

        # If the gui flag is set, prepend a 'gen_' on the filename to specify
        # this was generated by the GUI.
        if pref:
            name = "_".join([pref, name])

        # If dir is provided add this directory path to the filename.
        if dir:
            name = os.path.join(dir, name)
            home = os.getcwd()
            name = os.path.join(home, name)

        self.pln_filename = name

        if os.path.isfile(self.pln_filename):
            os.remove(self.pln_filename)

        with open(self.pln_filename, 'w') as new_pln:
            if disp:
                print("writing to {0}".format(self.pln_filename))

            # Use the pln_template dictionary to create the file sections and
            # look up the names that may be in the parameters dictionary.
            for section, fields in self.pln_template.items():

                # Recreate the section header for each new section.
                comment = "#* "
                separator = "=" * 48
                new_pln.write("".join([comment, separator, "\n"]))
                new_pln.write("".join([comment, section, "\n"]))
                new_pln.write("".join([comment, separator, "\n"]))

                # Look for attributes that match the field names defined in
                # the .pln template.
                for f in fields:
                    try:
                        exo_param = getattr(self, f.lower())
                    except AttributeError:
                        continue

                    # exo_param is now an ExoParameter object.  Add the
                    # keyword & value pair to the .pln file.
                    if is_empty(exo_param.value):
                        exo_param.value = exo_param.default
                    self._write_pln_line(new_pln, f, exo_param.value)

                    # Add additional keywords for uncertainties and references
                    # if they are present in the current ExoParameter.
                    if exo_param.uncertainty:
                        uf = "".join(["U", f])
                        self._write_pln_line(new_pln,
                                             uf,
                                             exo_param.uncertainty
                                             )
                    if exo_param.uncertainty_upper:
                        ufd = "".join(["U", f, "D"])
                        self._write_pln_line(new_pln,
                                             ufd,
                                             exo_param.uncertainty_upper
                                             )
                    if exo_param.reference:
                        fref = "".join([f, "REF"])
                        self._write_pln_line(new_pln,
                                             fref,
                                             exo_param.reference
                                             )
                    if exo_param.url:
                        furl = "".join([f, "URL"])
                        self._write_pln_line(new_pln,
                                             furl,
                                             exo_param.url
                                             )
Esempio n. 20
0
    def save_to_pln(self, name=None, dir=None, pref=None, disp=True):
        """
        Save an ExoPlanet object into a .pln text file.  A .pln template is
        needed here to recreate the sections of the text file and where to
        write each parameter.

        :param name:  The file name for the resulting .pln file.  This will be
                      automatically set to the exoplanet name if not provided,
                      but the user may supply a different name for testing.
        :type name:  str

        :param gui:  Flag used to alter the filename if this file is being
                     generated by the GUI.
        :type gui:  bool
        """

        # If name is not provided, use the NAME field value + .pln.
        if not name:
            name = ".".join([self.name.value, "pln"])

        # If the gui flag is set, prepend a 'gen_' on the filename to specify
        # this was generated by the GUI.
        if pref:
            name = "_".join([pref, name])

        # If dir is provided add this directory path to the filename.
        if dir:
            name = os.path.join(dir, name)
            home = os.getcwd()
            name = os.path.join(home, name)

        self.pln_filename = name

        if os.path.isfile(self.pln_filename):
            os.remove(self.pln_filename)

        with open(self.pln_filename, 'w') as new_pln:
            if disp:
                print("writing to {0}".format(self.pln_filename))

            # Use the pln_template dictionary to create the file sections and
            # look up the names that may be in the parameters dictionary.
            for section, fields in self.pln_template.items():

                # Recreate the section header for each new section.
                comment = "#* "
                separator = "=" * 48
                new_pln.write("".join([comment, separator, "\n"]))
                new_pln.write("".join([comment, section, "\n"]))
                new_pln.write("".join([comment, separator, "\n"]))

                # Look for attributes that match the field names defined in
                # the .pln template.
                for f in fields:
                    try:
                        exo_param = getattr(self, f.lower())
                    except AttributeError:
                        continue

                    # exo_param is now an ExoParameter object.  Add the
                    # keyword & value pair to the .pln file.
                    if is_empty(exo_param.value):
                        exo_param.value = exo_param.default
                    self._write_pln_line(new_pln, f, exo_param.value)

                    # Add additional keywords for uncertainties and references
                    # if they are present in the current ExoParameter.
                    if exo_param.uncertainty:
                        uf = "".join(["U", f])
                        self._write_pln_line(new_pln, uf,
                                             exo_param.uncertainty)
                    if exo_param.uncertainty_upper:
                        ufd = "".join(["U", f, "D"])
                        self._write_pln_line(new_pln, ufd,
                                             exo_param.uncertainty_upper)
                    if exo_param.reference:
                        fref = "".join([f, "REF"])
                        self._write_pln_line(new_pln, fref,
                                             exo_param.reference)
                    if exo_param.url:
                        furl = "".join([f, "URL"])
                        self._write_pln_line(new_pln, furl, exo_param.url)
Esempio n. 21
0
    def verify_pln(self):
        """
        Some last-second tweaks are needed for proper .pln file formatting.
        """

        warnings = []

        self._populate_uncertainties()

        # The transitref and transiturl actually end up stored in the 'transit'
        # ExoParam due to the ref and url splits.  Pull these out and set the
        # transit entries to the proper pointers.
        if self.transit.value == 1:
            if is_empty(self.transit.reference):
                self.transit.reference = "__TRANSITREF"
            if is_empty(self.transit.url):
                self.transit.url = "__TRANSITURL"

        # If the transit depth is not provided, but an Rp/R* ratio is,
        # calculate the depth value.
        if is_empty(self.depth.value) and is_valid(self.rr.value):
            self.depth.value = self.rr.value**2
            if isinstance(self.rr.uncertainty, Decimal):
                self.depth.uncertainty = self.rr.uncertainty * 2
            if isinstance(self.rr.uncertainty_upper, Decimal):
                self.depth.uncertainty_upper = self.rr.uncertainty_upper * 2
            self.depth.reference = "Calculated from Rp/R*"
            self.depth.url = self.rr.reference

        # If the orbital eccentricity value is 0 and a TT value is provided,
        # use the same values for T0 as well.
        if self.ecc.value == Decimal(0) and is_empty(self.om.value):
            self.om.value = Decimal(90)
            self.om.reference = "Set to 90 deg with ecc~0"
            print("set omega to 90")
            if is_valid(self.tt.value):
                print("copying TT to T0")
                self.t0.copy_values(self.tt)
        # OM may already be set to 90.
        elif self.ecc.value == 0 and self.om.value == 90:
            if str(self.tt.value) != "NaN":
                print("copying TT to T0")
                self.t0.copy_values(self.tt)

        # Set the FREEZE_ECC flag if ECC=0 and no uncertainty is provided.
        if self.ecc.value == 0 and is_empty(self.ecc.uncertainty):
            self.freeze_ecc.value = 1

        # Set the MULT flag if NCOMP is more than 1 planet.
        if self.ncomp.value > 1:
            self.mult.value = 1

        # Set the TREND flag if a DVDT value is provided.
        if not is_empty(self.dvdt.value):
            self.trend.value = 1

        # Exclude planets with period uncertainty >10%.
        self.per.check_constrained(0.1)
        if not self.per.well_constrained:
            self.exclude()
            warnings.append("<uncertain PER>")

        # Warn of planets with K speeds <2 m/s.
        if is_valid(self.k.value):
            if self.k.value < 2:
                # self.exclude()
                warnings.append("<low K value>")

        # Make sure RA string uses spaces.
        if not is_empty(self.ra_string.value):
            if "h" in self.ra_string.value:
                new_value = self.ra_string.value.replace("h", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value.replace("s", "")
                self.ra_string.value = new_value

        # Make sure DEC string uses spaces.
        if not is_empty(self.dec_string.value):
            if "d" in self.dec_string.value:
                new_value = self.dec_string.value.replace("d", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value.replace("s", "")
                self.dec_string.value = new_value

        # Display warnings generated by final adjustments.
        if len(warnings) > 0:
            print("<<<{0} GOT {1} WARNING(S)>>>".format(
                self.name.value, len(warnings)))
            [print(x) for x in warnings]
Esempio n. 22
0
    def read_from_nasa(self, nasa_series):
        """
        Construct an ExoPlanet from data scraped from the NASA ExoPlanet
        Archive.

        :param nasa_series:  This function expects a data pulled for a single
                             matching exoplanet.
        :type nasa_series:  pandas.Series
        """

        # Transform the Pandas Series containing NASA parameters into a dict.
        nasa_dict = nasa_series.to_dict()

        # Look for every attribute added during ExoPlanet initialization.
        for att in self.attributes:

            # getattr will return an ExoParameter object for this attribute.
            exo_param = getattr(self, att)

            # Check for a corresponding data field in the NASA data.
            nasa_field = exo_param.nasa_field
            if nasa_field is None:
                continue

            # Get the NASA value and apply some changes based on which
            # ExoParameter we are working on.
            new_value = nasa_dict[nasa_field]
            if is_empty(new_value):
                new_value = exo_param.default

            # Remove 'd', 'm', 's' from the DEC string and fill with ' '.
            elif nasa_field == "dec_str":
                new_value = new_value.replace("d", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value[:-1]

            # NASA hd_name includes the planet letter, so cut that off.
            elif nasa_field == "hd_name":
                new_value = " ".join(new_value.split(" ")[:-1])

            # NASA hip_name includes the planet letter, so cut that off.
            elif nasa_field == "hip_name":
                new_value = " ".join(new_value.split(" ")[:-1])

            # NASA provides transit depth values in percentages, we just want
            # the decimal value.
            elif nasa_field == "pl_trandep" and is_valid(new_value):
                new_value = Decimal(new_value) / 100

            # Remove 'h', 'm', 's' from the RA string and fill with ' '.
            elif nasa_field == "ra_str":
                new_value = new_value.replace("h", " ")
                new_value = new_value.replace("m", " ")
                new_value = new_value[:-1]

            # If no RV measurements are listed in NASA, we want to use -1 for
            # our NOBS.
            elif nasa_field == "st_nrvc" and new_value == "0":
                new_value = -1

            # Try changing the new value into a Decimal.
            try:
                exo_param.value = Decimal(new_value)
            except (InvalidOperation, TypeError):
                exo_param.value = new_value

            # Try looking for corresponding uncertainty values in the NASA
            # data.
            if exo_param.uncertain_flag:

                # Create the two error column fields (for + and - uncertainty).
                nasa_err1 = "".join([nasa_field, "err1"])
                nasa_err2 = "".join([nasa_field, "err2"])

                # Pull values from these columns if they exist.
                try:
                    shi = str(nasa_dict[nasa_err1])
                    exo_param.uncertainty_upper = Decimal(shi)

                    # NASA data stores lower uncertainty as a negative number.
                    slo = str(nasa_dict[nasa_err2])
                    exo_param.uncertainty_lower = Decimal(slo) * -1

                except KeyError:
                    pass

            # Reset the current ExoPlanet attribute to the now-updated
            # ExoParameter.
            setattr(self, att, exo_param)