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