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.
The exposure time (s)
The effective collecting area of the telescope (cm^2)
The quantum efficiency (QE) of the collector (e-/photon)
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:
erg/nm/cm^2/s or erg/A/cm^2/s (use
flux_type='flambda'
)erg/Hz/cm^2/s (use
flux_typ='fnu'
)photons/nm/cm^2/s or photons/A/cm^2/s (use
flux_typ='fphotons'
)Any units that qualify as an
astropy.units.spectral_density
using the AstroPyunits
moduledimensionless (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 arbitraryfloat
valueunit1
andunit2
are arbitraryAngleUnit
instancestheta1
andtheta2
are arbitraryAngle
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.
- 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
- 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.