Пример #1
0
    def _add_and_adjust_physical_unit(self, other, sign_self, sign_other):
        """Add/subtract LogUnit to/from another unit, and adjust physical unit.

        self and other are multiplied by sign_self and sign_other, resp.

        We wish to do:   ±lu_1 + ±lu_2  -> lu_f          (lu=logarithmic unit)
                  and     pu_1^(±1) * pu_2^(±1) -> pu_f  (pu=physical unit)

        Raises
        ------
        UnitsError
            If function units are not equivalent.
        """
        # First, insist on compatible logarithmic type. Here, plain u.mag,
        # u.dex, and u.dB are OK, i.e., other does not have to be LogUnit
        # (this will indirectly test whether other is a unit at all).
        try:
            getattr(other, 'function_unit', other)._to(self._function_unit)
        except AttributeError:
            # if other is not a unit (i.e., does not have _to).
            return NotImplemented
        except UnitsError:
            raise UnitsError("Can only add/subtract logarithmic units of"
                             "of compatible type.")

        other_physical_unit = getattr(other, 'physical_unit',
                                      dimensionless_unscaled)
        physical_unit = CompositeUnit(
            1, [self._physical_unit, other_physical_unit],
            [sign_self, sign_other])

        return self._copy(physical_unit)
Пример #2
0
    def __new__(cls, flux, wavelength, scale=None, unit=Angstrom,
                wavelength_unit=Angstrom, ivar=None, std=None,
                mask=None, dtype=None, copy=True, pixmask_flag=None, **kwargs):

        flux = np.array(flux)

        # If the scale is defined, creates a new composite unit with the input scale.
        if scale is not None:
            unit = CompositeUnit(unit.scale * scale, unit.bases, unit.powers)

        obj = Quantity(flux, unit=unit, dtype=dtype, copy=copy)
        obj = obj.view(cls)
        obj._set_unit(unit)

        obj.ivar = np.array(ivar) if ivar is not None else None
        obj.mask = np.array(mask) if mask is not None else None

        if std is not None:
            assert ivar is None, 'std and ivar cannot be used at the same time.'
            obj._std = np.array(std)

        assert wavelength is not None, 'invalid wavelength'

        if isinstance(wavelength, Quantity):
            obj.wavelength = wavelength
        else:
            obj.wavelength = np.array(wavelength) * wavelength_unit

        obj.pixmask_flag = pixmask_flag

        return obj
Пример #3
0
def divide_units_reverse(unit_a, unit_b):
    """
    This function ...
    :param unit_a:
    :param unit_b:
    :return:
    """

    # Re-evaluate everything, cannot be a photometric quantityb anymore
    return CompositeUnit(1, [unit_b, unit_a], [1, -1], _error_check=False)
Пример #4
0
def analyse_unit(unit):
    """
    This function ...
    :param unit:
    :return:
    """

    # Initialize different parts of the unit
    scale_factor = unit.scale
    base_unit = Unit("")
    wavelength_unit = Unit("")
    frequency_unit = Unit("")
    length_unit = Unit("")
    solid_angle_unit = Unit("")

    #print("BEFORE", unit)
    #print(unit)

    # Reduce (for example, convert 'Jy * Hz' to '1e-26 W / m2')
    unit, cannot_be_intrinsic_brightness = reduce_unit(unit)

    #print(unit)
    #print("AFTER", unit)

    # Look in the bases whether different physical types occur twice
    for physical_type in ["frequency", "time", "length", "solid angle"]:

        occurences = occurences_for_type(unit, physical_type)

        #print(occurences)

        # Powers are
        if len(occurences) == 2:

            base_a = occurences[0][0]
            base_b = occurences[1][0]

            power_a = occurences[0][1]
            power_b = occurences[1][1]

            if power_a == -power_b:

                # Eliminate this physical type from the unit

                # Calculate the ratio of the two units
                ratio = (base_a / base_b).to("")

                # To the power
                factor = ratio**power_a

                # Eliminate first base unit
                unit *= base_a**(-power_a)
                unit *= base_b**(-power_b)

                # Correct with factor
                unit = CompositeUnit(factor * unit.scale, unit.bases,
                                     unit.powers)

    #print(unit)
    #print(unit.bases)

    # Loop over the bases
    for base, power in zip(unit.bases, unit.powers):

        if power > 0:

            # We have spectral flux density (e.g. Jy) as a base unit
            if base.physical_type == "spectral flux density":

                # Decompose the unit
                sf, bu, wu, fu, du, su, _ = analyse_unit(base.represents)

                scale_factor *= sf
                base_unit *= bu

                # Wavelength unit
                if wu != "":

                    if fu != "":
                        raise ValueError(
                            "Wavelength unit and frequency unit cannot both be defined"
                        )
                    if wavelength_unit != "":
                        raise ValueError("Encountered two wavelength units: " +
                                         str(wavelength_unit) + " and " +
                                         str(wu))
                    wavelength_unit = wu

                # Frequency unit
                if fu != "":

                    if wu != "":
                        raise ValueError(
                            "Wavelength unit and frequency unit cannot both be defined"
                        )
                    if frequency_unit != "":
                        raise ValueError("Encountered two frequency units: " +
                                         str(frequency_unit) + " and " +
                                         str(fu))

                    frequency_unit = fu

                # Distance unit
                if du != "":

                    if length_unit != "":
                        raise ValueError("Encountered two length units: " +
                                         str(length_unit) + " and " + str(du))
                    length_unit = du

                    # We cannot have an intrinsic brightness (in other words, the length unit IS A DISTANCE LENGTH UNIT, NOT AN INTRINSIC LENGTH SCALE)
                    cannot_be_intrinsic_brightness = True

                # Solid angle unit
                if su != "":

                    if solid_angle_unit != "":
                        raise ValueError(
                            "Encountered two solid angle units: " +
                            str(solid_angle_unit) + " and " + str(su))
                    solid_angle_unit = su

            # Unit of power
            elif base.physical_type == "power":

                if power != 1:
                    raise ValueError("Found a power of " + str(power) +
                                     " for a unit of radiative power")
                if base_unit != "":
                    raise ValueError(
                        "Found a unit of power but base unit already defined by '"
                        + str(base_unit) + "'")
                base_unit = base

            # Unit of energy
            elif base.physical_type == "energy":

                if power != 1:
                    raise ValueError("Found a power of " + str(power) +
                                     " for a unit of energy")
                if base_unit != "":
                    raise ValueError(
                        "Found a unit of energy but base unit already defined by '"
                        + str(base_unit) + "'")
                base_unit = base

            # Unknown
            elif base.physical_type == "unknown":
                base_unit *= base**power

                # Else
            else:
                raise ValueError("Not a photometric unit: found " +
                                 base.physical_type + "^" + str(power) +
                                 " dimension as a base")

        # Time unit
        elif base.physical_type == "time":

            # Check the power
            if power != -1:
                raise ValueError(
                    "Found a unit of time but not as inversely proportional to the base unit (instead the power is "
                    + str(power) + ")")
            base_unit *= base**power

        # Length unit
        elif base.physical_type == "length":

            # Check the power
            if power == -1: wavelength_unit = base
            elif power == -2: length_unit = base**2
            elif power == -3:
                wavelength_unit = base
                length_unit = base**2
            else:
                raise ValueError("Not a photometric unit: found length^" +
                                 str(power) + " dimension")

        # Frequency unit
        elif base.physical_type == "frequency":

            if power != -1:
                raise ValueError(
                    "Found a unit of frequency but not as inversely proportional to the base unit (instead the power is "
                    + str(power) + ")")
            frequency_unit = base

        # Solid angle unit
        elif base.physical_type == "solid angle":

            if power != -1:
                raise ValueError(
                    "Found a unit of solid angle but not as inversely proportional to the base unit (instead the power is "
                    + str(power) + ")")
            solid_angle_unit = base

        # Angle unit
        elif base.physical_type == "angle":

            if solid_angle_unit != "":
                raise ValueError(
                    "Found an angle unit but the solid angle unit is already defined: "
                    + str(solid_angle_unit))
            if power != -2:
                raise ValueError(
                    "Found an angle unit but not as squared inversely proportional to the base unit (instead the power is "
                    + str(power) + ")")
            solid_angle_unit = base**power

    # Check if wavelength and frequency unit are not both defined
    if wavelength_unit != "" and frequency_unit != "":
        raise ValueError(
            "Not a photometric unit: found wavelength^-1 and frequency^-1 dimensions"
        )

    # Check whether a base unit is found
    if base_unit is None or base_unit == "":
        raise ValueError(
            "Not a photometric unit: found no unit of energy or luminosity")

    # Return
    return scale_factor, base_unit, wavelength_unit, frequency_unit, length_unit, solid_angle_unit, cannot_be_intrinsic_brightness
Пример #5
0
def reduce_unit(unit):
    """
    This function ...
    :param unit: 
    :return: 
    """

    base_types = physical_base_types_units_and_powers_as_dict(unit, power=1)

    #print("BASE TYPES", base_types)

    # Flag that is set to True when things as Jy are encountered, which allows us to say that we are not dealing with intrinsic surface brightnesses, but with fluxes
    cannot_be_intrinsic_brightness = False

    # If we have a combination of a flux density and a frequency
    if "spectral flux density" in base_types and "frequency" in base_types:

        # If they occur more than once, we have something weird
        if len(base_types["spectral flux density"]) == 1 and len(
                base_types["frequency"]) == 1:

            # Assert power is one
            assert base_types["spectral flux density"][0][1] == 1

            # We have a flux, so no intrinsic brightness
            cannot_be_intrinsic_brightness = True

            # Replace the flux density unit with the decomposed version
            represents = base_types["spectral flux density"][0][0].represents

            #print("REPRESENTS", represents, type(represents), represents.physical_type)
            #print("REPRESENTS x2", represents.represents)

            #flux_density_base_types = physical_base_types_units_and_powers_as_dict(represents)
            #print("REPRESENTS x2", flux_density_base_types)

            # ACCOMODATING THE FACT THAT FOR FOR EXAMPLE MJy, .REPRESENTS RESULTS IN 1e6 Jy, INSTEAD OF IMMEDIATELY
            # 1e6 W / Hz / m2 !!!!
            if represents.physical_type == "spectral flux density":

                factor = represents.scale
                bases = represents.bases
                powers = represents.powers
                #represents = represents.represents

                #print(factor)
                #print(bases)
                #print(powers)

                # If the number of bases is NOT one, we have the 'normal' case, where Jy is decomposed into W, Hz and m
                # and factor, bases and powers will be 1e-26, [Unit("W"), Unit("Hz"), Unit("m")], and [1, -1, -2]
                if len(bases) == 1:

                    # This is almost impossible, but check anyway
                    if powers[0] != 1:
                        raise RuntimeError("Something went wrong")

                    # Decompose again
                    base = bases[0]
                    base_represents = base.represents

                    # Set represents
                    #represents = base_represents
                    #represents._scale *= factor

                    represents = CompositeUnit(base_represents.scale * factor,
                                               base_represents.bases,
                                               base_represents.powers)

                # Not one: do nothing
                else:
                    pass

            #print("REPRESENTS", represents)

            # Replace
            unit /= base_types["spectral flux density"][0][0]
            unit *= represents

        # Invalid
        elif len(base_types["spectral flux density"]) > 1:
            raise ValueError(
                "Invalid photometric unit: multiple occurences of spectral flux base unit"
            )
        elif len(base_types["frequency"]) > 1:
            raise ValueError(
                "Invalid photometric unit: multiple occurences of frequency base unit"
            )

    # If we have a combination of a flux density and a length to the power of 2
    if "spectral flux density" in base_types and "length" in physical_base_types(
            unit, power=2):

        # if they occur more than once, we have something weird
        if len(base_types["spectral flux density"]) == 1:

            # Assert power is one
            assert base_types["spectral flux density"][0][1] == 1

            # Can still be intrinsic brightness if distance dependence is done away with and another is added (e.g. * m2 / pc2)

            # Replace the flux density unit with the decomposed version
            represents = base_types["spectral flux density"][0][0].represents

            # Replace
            unit /= base_types["spectral flux density"][0][0]
            unit *= represents

        # Invalid
        else:
            raise ValueError(
                "Invalid photometric unit: multiple occurences of spectral flux base unit"
            )

    # Return the unit
    return unit, cannot_be_intrinsic_brightness