Units

Size Units

GalSim models surface brightnesses of objects in sky coordinates. The physical size of a galaxy in light years or kpc is not really relevant to its appearance in the sky. Rather, the size is an angle, being the angle subtended by the galaxy as seen from Earth.

The most common choice of unit for these objects is arcseconds. This happens to be the right order of magnitude for most objects of astronomical interest. The smallest objects we typically observe are somewhat less than an arcsecond in size. The largest objects (e.g. M31) are more than a degree, but by far the majority of the objects of interest are only a few arcseconds across.

So this is usually the units one would use for the various GSObject size parameters (e.g. fwhm, half_light_radius and so forth) when you are building them. However, this choice is actually up to the user. You may choose to define all your sizes in degrees or radians if you want. You just need to be consistent with the unit you use for the sizes of all your objects and with the units of the pixel scale when you are building your Image (via the scale parameter of the Image constructor) or when drawing (the scale argument to GSObject.drawImage)

Note

If you are using a more complicated WCS than a simple PixelScale (i.e. using wcs when building the Image rather than scale), then you need to be even more careful about this. Some of the FITS-based WCS classes assume you are using arcseconds for the distance unit, and it is not always easy to coerce them into using a different unit. In these cases, you are probably well-advised to just stick with arcseconds for your sizes.

Some classes specify their angular sizes somewhat indirectly. For the Airy class, for instance, you can specify lam as the wavelength of the light (\(\lambda\), say at the middle of the bandpass) in nm, and diam, the telescope diameter (\(D\)) in meters. The ratio of these \(\lambda / D\) (after putting them into the same units) gives the fundamental scale radius for an Airy profile. But this angle is in radians, which is normally not particularly convenient to use for the image pixel scale. The Airy constructor thus takes another parameter, scale_unit, which defaults to arcsec to specify the unit you want to convert this angle to.

Flux Units

The units for the flux of a GSObject are nominally photons/cm^2/s, and the units for an image are ADUs (analog-to-digital units). There are thus four conversion factors to apply to go from one to the other.

  1. The exposure time (s)

  2. The effective collecting area of the telescope (cm^2)

  3. The quantum efficiency (QE) of the collector (e-/photon)

  4. The gain of the read-out amplifier (e-/ADU)

In GalSim, we generally just lump the QE in with the gain, so our gain is taken to have units of photons/ADU, and it really represents gain / QE.

Note, however, that the default exposure time, telescope collecting area, and gain are 1 s, 1 cm^2, and 1 ADU/photon respectively, so users who wish to ignore the intricacies of managing exposure times, collecting areas, and gains can simply think of the flux of a GSObject in either ADUs or photons.

However, if you prefer to think of your flux as having physical units, then you can declare the appropriate telescope collecting area (area), the exposure time (exptime), and the total effective gain (gain) as arguments to GSObject.drawImage.

SED Units

These details matter more when working with ChromaticObject instances, where the flux normalization is handled with an SED object. The units of an input SED can be any of several possible options:

  1. erg/nm/cm^2/s or erg/A/cm^2/s (use flux_type='flambda')

  2. erg/Hz/cm^2/s (use flux_typ='fnu')

  3. photons/nm/cm^2/s or photons/A/cm^2/s (use flux_typ='fphotons')

  4. Any units that qualify as an astropy.units.spectral_density using the AstroPy units module

  5. dimensionless (use flux_typ='1')

Note

The last one is a bit different from the others. It is generally only appropriate for the “SED” of a PSF, not that of a galaxy or star. The PSF may have a different effect as a function of wavelength, in which case that can be treated similarly to how we treat an SED. In any object that is a convolution of several components, only one of them should have a spectral SED. The rest should be dimensionless (possibly flat). The net SED of the composite object will then also be spectral.

Internally, all spectral units are converted to photons/nm/cm^2/s. Then when drawing a ChromaticObject, spectrum is integrated over the Bandpass to obtain the normal units of photons/cm^2/s. If you trust your SED, you can then just draw with the appropriate area, exptime and gain when you call ChromaticObject.drawImage.

However, it is often more convenient to target a particular flux or magnitude of your object as observed through a particular Bandpass (probably in ADU) and then ignore all of these parameters when you are drawing. This is possible using the methods SED.withFlux or SED.withMagnitude.

Angles

For nearly all angular values, we require the argument to be an Angle instance. We use the LSSTDESC.Coord package for this (and its CelestialCoord class):

https://github.com/LSSTDESC/Coord

An earlier version of this code was originally implemented in GalSim, so we still import the relevant classes into the galsim namespace, so for example gasim.Angle is a valid alias for coord.Angle. You may therefor use either namespace for your use of these classes.

class galsim.Angle(theta, unit=None)[source]

A class representing an Angle. Angles are a value with an AngleUnit.

Initialization:

You typically create an Angle by multiplying a number by a coord.AngleUnit, for example:

>>> pixel = 0.27 * arcsec
>>> ra = 13.4 * hours
>>> dec = -32 * degrees
>>> from math import pi
>>> theta = pi/2. * radians

You can also initialize explicitly, taking a value and a unit:

coord.Angle.__init__()

>>> unit = AngleUnit(math.pi / 100)  # gradians
>>> phi = Angle(90, unit)

Built-in units:

There are five built-in AngleUnits which are always available for use:

coord.radians:

coord.AngleUnit(1.)

coord.degrees:

coord.AngleUnit(pi / 180.)

coord.hours:

coord.AngleUnit(pi / 12.)

coord.arcmin:

coord.AngleUnit(pi / 180. / 60.)

coord.arcsec:

coord.AngleUnit(pi / 180. / 3600.)

Attribute:

Since extracting the value in radians is extremely common, we have a read-only attribute to do this quickly:

rad:

The measure of the unit in radians.

For example:

>>> theta = 90 * degrees
>>> print(theta.rad)
1.5707963267948966

It is equivalent to the more verbose:

>>> x = theta / radians
>>> print(x)
1.5707963267948966

but without actually requiring the floating point operation of dividing by 1.

Arithmetic:

Allowed arithmetic with Angles include the following. In the list below,

  • x is an arbitrary float value

  • unit1 and unit2 are arbitrary AngleUnit instances

  • theta1 and theta2 are arbitrary Angle instances

>>> x = 37.8
>>> unit1 = arcmin
>>> unit2 = degrees
>>> theta1 = x * unit1
>>> theta2 = x * unit2
>>> x2 = theta1 / unit2
>>> theta = theta1 + theta2
>>> theta = theta1 - theta2
>>> theta = theta1 * x
>>> theta = x * theta1
>>> theta = theta1 / x
>>> theta = -theta1
>>> theta += theta1
>>> theta -= theta1
>>> theta *= x
>>> theta /= x
>>> x = unit1 / unit2   # equivalent to x = (1 * unit1) / unit2

The above operations on NumPy arrays containing Angles are permitted as well.

Trigonometry:

There are convenience function for getting the sin, cos, and tan of an angle, along with one for getting sin and cos together, which should be more efficient than doing sin and cos separately:

coord.Angle.sin()
coord.Angle.cos()
coord.Angle.tan()
coord.Angle.sincos()
>>> sint = theta.sin()  # equivalent to sint = math.sin(theta.rad)
>>> cost = theta.cos()  # equivalent to cost = math.cos(theta.rad)
>>> tant = theta.tan()  # equivalent to tant = math.tan(theta.rad)
>>> sint, cost = theta.sincos()

These functions mean that numpy trig functions will work on Angles or arrays of Angles:

>>> sint = np.sin(theta)
>>> cost = np.cos(theta)
>>> tant = np.tan(theta)

Wrapping:

Depending on the context, theta = 2pi radians and theta = 0 radians may mean the same thing. If you want your angles to be wrapped to [-pi,pi) radians, you can do this by calling

coord.Angle.wrap()

>>> theta = theta.wrap()

This could be appropriate before testing for the equality of two angles for example, or calculating the difference between them.

There is also an option to wrap into a different 2 pi range if so desired by specifying the center of the range.

cos()[source]

Return the cos of an Angle.

property deg

Return the Angle in degrees.

Equivalent to angle / coord.degrees

dms(sep=':', prec=None, pad=True, plus_sign=False)[source]

Return a DMS representation of the angle as a string: +-dd:mm:ss.decimal An optional sep parameter can change the : to something else (e.g. a space or nothing at all).

Note: the reverse process is effected by Angle.from_dms():

>>> angle = -(5 * degrees + 21 * arcmin + 25.2 * arcsec)
>>> dms = angle.dms()
>>> print(dms)
-05:21:25.2
>>> angle2 = Angle.from_dms(dms)
>>> print(angle2 / degrees)
-5.356999999999999
Parameters:
  • sep – The token to put between the hh and mm and beteen mm and ss. This may also be a string of 2 or 3 items, e.g. ‘dm’ or ‘dms’. Or even a tuple of strings such as (‘degrees ‘, ‘minutes ‘, ‘seconds’). [default: ‘:’]

  • prec – The number of digits of precision after the decimal point. [default: None]

  • pad – Whether to pad with a leading 0 if necessary to make h 2 digits. [default: True]

  • plus_sign – Whether to use a plus sign for positive angles. [default: False]

Returns:

a string of the DMS representation of the angle.

static from_dms(str)[source]

Convert a string of the form dd:mm:ss.decimal into an Angle.

There may be an initial + or - (or neither), then two digits for the degrees, two for the minutes, and two for the seconds. Then there may be a decimal point followed by more digits. There may be a colon separating dd, mm, and ss, or whitespace, or nothing at all. In fact, the code will ignore any non-digits between the degrees, minutes, and seconds.

Note: the reverse process is effected by Angle.dms():

>>> angle = -(5 * degrees + 21 * arcmin + 25.2 * arcsec)
>>> dms = angle.dms()
>>> print(dms)
-05:21:25.2
>>> angle2 = Angle.from_dms(dms)
>>> print(angle2 / degrees)
-5.356999999999999
Parameters:

str – The string to parse.

Returns:

the corresponding Angle instance

static from_hms(str)[source]

Convert a string of the form hh:mm:ss.decimal into an Angle.

There may be an initial + or - (or neither), then two digits for the hours, two for the minutes, and two for the seconds. Then there may be a decimal point followed by more digits. There may be a colon separating hh, mm, and ss, or whitespace, or nothing at all. In fact, the code will ignore any non-digits between the hours, minutes, and seconds.

Note: the reverse process is effected by Angle.hms():

>>> angle = -5.357 * hours
>>> hms = angle.hms()
>>> print(hms)
-05:21:25.2
>>> angle2 = Angle.from_hms(hms)
>>> print(angle2 / hours)
-5.356999999999999
Parameters:

str – The string to parse.

Returns:

the corresponding Angle instance

hms(sep=':', prec=None, pad=True, plus_sign=False)[source]

Return an HMS representation of the angle as a string: +-hh:mm:ss.decimal.

An optional sep parameter can change the : to something else (e.g. a space or nothing at all).

Note: the reverse process is effected by Angle.from_hms():

>>> angle = -5.357 * hours
>>> hms = angle.hms()
>>> print(hms)
-05:21:25.2
>>> angle2 = Angle.from_hms(hms)
>>> print(angle2 / hours)
-5.356999999999999
Parameters:
  • sep – The token to put between the hh and mm and beteen mm and ss. This may also be a string of 2 or 3 items, e.g. ‘hm’ or ‘hms’. Or even a tuple of strings such as (‘hours ‘, ‘minutes ‘, ‘seconds’). [default: ‘:’]

  • prec – The number of digits of precision after the decimal point. [default: None]

  • pad – Whether to pad with a leading 0 if necessary to make h,m,s 2 digits. [default: True]

  • plus_sign – Whether to use a plus sign for positive angles. [default: False]

Returns:

a string of the HMS representation of the angle.

property rad

Return the Angle in radians.

Equivalent to angle / coord.radians

sin()[source]

Return the sin of an Angle.

sincos()[source]

Return both the sin and cos of an Angle as a numpy array [sint, cost].

tan()[source]

Return the tan of an Angle.

wrap(center=None)[source]

Wrap Angle to lie in the range [-pi, pi) radians (or other range of 2pi radians)

Depending on the context, theta = 2pi radians and theta = 0 radians are the same thing. If you want your angles to be wrapped to [-pi, pi) radians, you can do this as follows:

>>> theta = Angle(700 * degrees)
>>> theta = theta.wrap()
>>> print(theta.deg)
-19.99999999999998

This could be appropriate before testing for the equality of two angles for example, or calculating the difference between them.

If you want to wrap to a different range than [-pi, pi), you can set the center argument to be the desired center of the the range. e.g. for return values to fall in [0, 2pi), you could call

>>> theta = theta.wrap(center=180. * degrees)
>>> print(theta / degrees)
340.0
Parameters:

center – The center point of the wrapped range. [default: 0 radians]

Returns:

the equivalent angle within the range [center-pi, center+pi)

galsim._Angle(theta)[source]

Equivalent to Angle(theta, coord.radians), but without the normal overhead (which isn’t much to be honest, but this is nonetheless slightly quicker).

Parameters:

theta – The numerical value of the angle in radians.

class galsim.AngleUnit(value)[source]

A class for defining angular units used by Angle objects.

Initialization:

An AngleUnit takes a single argument for initialization, a float that specifies the size of the desired angular unit in radians. For example:

coord.AngleUnit.__init__()

>>> gradian = AngleUnit(2. * math.pi / 400.)
>>> print(gradian)
coord.AngleUnit(0.015707963267948967)

Built-in units:

There are five built-in AngleUnits which are always available for use:

coord.radians:

coord.AngleUnit(1.)

coord.degrees:

coord.AngleUnit(pi / 180.)

coord.hours:

coord.AngleUnit(pi / 12.)

coord.arcmin:

coord.AngleUnit(pi / 180. / 60.)

coord.arcsec:

coord.AngleUnit(pi / 180. / 3600.)

Attribute:

An AngleUnit as the following (read-only) attribute:

value:

The measure of the unit in radians.

static from_name(unit)[source]

Convert a string into the corresponding AngleUnit.

Only the start of the string is checked, so for instance ‘radian’ or ‘radians’ is equivalent to ‘rad’.

Valid options are:

rad:

AngleUnit(1.)

deg:

AngleUnit(pi / 180.)

hour or hr:

AngleUnit(pi / 12.)

arcmin:

AngleUnit(pi / 180. / 60.)

arcsec:

AngleUnit(pi / 180. / 3600.)

Note: these valid names are listed in AngleUnit.valid_names.

Parameters:

unit – The string name of the unit to return

Returns:

an AngleUnit

property value

A read-only attribute giving the measure of the AngleUnit in radians.