Design Principles¶
All sbpy
code must be written according to the following design principles.
Physical parameters are quantities¶
If a variable has units of length, time, flux density, magnitude, etc., then it must be an
astropy
Quantity
.Inputs may be type and unit checked with the
quantity_input
decorator.Note magnitudes may also carry physical units. Compare
astropy.units.mag
(unitless) toastropy.units.ABmag
(flux density per unit frequency), andsbpy.units.VEGAmag
(units of Vega spectral flux density).
Epochs must be Time objects¶
Any kind of epoch or point in time must be of type
Time
; time scales must be properly set and propagated through all functions.
Use sbpy DataClass
objects¶
Orbit
,Phys
,Ephem
, andObs
are thesbpy
DataClass
objects. See Data Module (sbpy.data) for details.All inputs based on ephemeris, orbit, and physical parameters must use these classes.
The classes enable easy parameter passing from online sources. Compare the following:
eph = Ephem.from_horizons('2P') # rh, delta required, phase angle is optional: Afrho(wave, fluxd, aper, eph['rh'], eph['delta'], phase=eph['phase']) # more to the point: Afrho(wave, fluxd, aper, eph)
Carefully document which fields are used by your function or method.
Dictionary-like objects may be allowed for user input, but should be internally converted to a
DataClass
object with thedataclass_input
decorator:@dataclass_input(eph=Ephem) def H11(eph): ...
The same, but using function annotations:
@dataclass_input def H11(eph: Ephem): ...
Exceptions are allowed when only one parameter is needed, e.g.,
phase_func(phase)
. But instead consider using the relevantDataClass
object, and decorating the function withquantity_to_dataclass
:@quantity_to_dataclass(eph=(Ephem, 'phase')) def phase_func(eph): ...
The decorator may be stacked with
dataclass_input
for maximum flexibility:@dataclass_input @quantity_to_dataclass(eph=(Ephem, 'phase')) def phase_func(eph): ...
Append fields to DataClass
at the user’s request¶
If a function takes a
DataClass
object as input, the results of this function may be optionally appended to this object, if appropriate.Use the keyword argument
append_results
.If
True
, add the data to theDataClass
object as new fields, and return the result.
Cite relevant works¶
All important references for methods, data sources, parameters, software, etc., must be cited.
Citations may be executed internally with
sbpy.bib.register()
, or via thecite
decorator:@cite({'method': '1687pnpm.book.....N'}) def force(mass, acceleration): return mass * acceleration
Labels describing references (
'method'
in the above example) are required to start with the following strings:'method'
(for general method descriptions),'data source'
(for data provenance referencing),'parameter'
(for use of specific parameters),'software'
(for use of specific software packages). Each of these labels can be suffixed at the users discretion (e.g.,`parameter: beaming parameter'
defines a reference for the value used for the beaming parameter).
Exceptions for private functions or speed¶
Quantity
andDataClass
objects are not required for private methods or functions requiring high performance.If a high-performance method is needed, consider writing two methods: one that uses the
Quantity
and/orDataClass
objects, and a second that is unitless.To simplify code maintenance and testing, the
Quantity
-loaded method should call the unitless method.