Package: cspyce
PyPI ReleaseTest StatusCode CoveragecspyceMODULE OVERVIEWVersion 2.x, originally released March, 2022 (see above for current installable
version)PDS Ring-Moon Systems Node, SETI Institutecspyceis a Python module that provides an interface to the C-language CSPICE
library produced by the Navigation and Ancillary Information Facility
(NAIF) of NASA's Planetary Data System (PDS).
It implements most functions of CSPICE in a Python-like way, while also
supporting numerous enhancements, including support for Python exceptions,
array inputs, and aliases.cspycemay be installed by runningpip install cspyce.Python versions 3.8 thru 3.12 are currently supported, with pre-built wheels
available for Linux, MacOS, and Windows.If you are looking for information on running or distributing this code from
the GitHub sources, look at the fileREADME-developers.mdin this directory.PYTHONIZATIONcspycehas been designed to replicate the core features of CSPICE for
users who wish to translate a program that already exists. Function names incspycematch their CSPICE names.However, it is also designed to behave as much as possible like a normal
Python module. To that end, it has the following features.The C language requires buffers to be allocated for output and it requires
array sizes to be included for both input and output. Thecspycemodule,
instead, eliminates all extraneous inputs, and all output arguments are
returned as a list (or as a single object if the function only returns one
item).cspycehas been fully integrated with Python's exception handling;
programmers can still opt to use CSPICE's error handling mechanism if they
wish to.Allcspycefunctions can handle positional arguments as well as arguments
passed by name.Allcspycefunctions have informative docstrings, so typinghelp(function)provides useful information.Manycspycefunctions take sensible default values if input arguments are
omitted.Allcspycefunctions that take filename arguments now supportpath-like-arguments.
A path-like argument could be a strings, a byte string, or apathlib.Path.
Thepathlib.Pathclass provides an
object-oriented class for manipulating file-system paths and performing common operations
on files.ENHANCEMENTSIn addition, thecspycemodule takes advantage of features of the Python
language to provide numerous options about how the functions perform their work.
These options include:Whether to return a CSPICE-style error condition or to raise a Python
exception.How to handle CSPICE functions that return a status flag, e.g., "found" or
"ok", instead of using the CSPICE toolkit's error handling mechanism.Whether to allowcspycefunctions to accept arrays of inputs all at once,
rather than looping through inputs in Python.Whether to automate the translation between SPICE body and frame IDs and their
associated names.Whether to allowcspyceto support aliases, in which the same body or frame
is associated with alternative names or IDs.EXCEPTION HANDLINGIn CSPICE, the user can designate what to do in the event of an error condition
using the functionerract(). In CSPICE, the available options are "RETURN",
"REPORT", "IGNORE", "ABORT", and "DEFAULT". Thecspyceversion of this
function adds new options "EXCEPTION" and "RUNTIME" to the suite of error
handling options supported by CSPICE.As usual, the user can select the exception handling mechanism to use by
calling the function erract(). Incspyce, the default is "EXCEPTION".When using the "EXCEPTION" option, each CSPICE error condition raises a
Python exception rather than setting thefailed()flag. The exception
contains the text of the CSPICE error, in the form (short message + " -- " +
long message). The CSPICE error conditions are mapped to standard Python
exception types in a sensible way:KeyErrorindicates that a SPICE ID or name is unrecognized.ValueErrorindicates that one of the inputs to a function had an invalid
value.TypeErrorindicates that one of the inputs to a function had an invalid
type.IndexErrorindicates that an integer index is out of range.IOErrorindicates errors with reading and writing files, including SPICE
kernels. IOError can also indicate that needed information was not in one
of the furnished kernels.MemoryErrorindicates that adequate memory could not be allocated, or
that the defined size of a memory buffer in C is too small.ZeroDivisionErrorindicates that a divide-by-zero has occurred.RuntimeErrorindicates that an action is incompatible with some aspect
of the CSPICE module's internal configuration.When using one of CSPICE's intrinsic error handling methods, no exception
will be raised, but a call tofailed()will reveal whether an error has
occurred. A call toreset()is needed to clear the error.Care has been taken to reduce the chances that the "dangerous" options
"IGNORE" and "REPORT" will cause a segmentation fault. However, this
possibility cannot be entirely ruled out, so caution is advised.Because it would be a highly questionable thing to do, the "ABORT" and
"DEFAULT" options are overridden by "EXCEPTION" when the user is runningcspycefrom an interactive shell. However, they resume their standard
effects during non-interactive runs.When using the "RUNTIME" option, each CSPICE error condition raises a
PythonRuntimeErrorexception rather than setting thefailed()flag. This
is similar to the "EXCEPTION" option except the type of exception is always
the same.Certain out-of-memory conditions are beyond the control of the CSPICE
library. These will always raise a MemoryError exception, regardless of the
exception handling method chosen.HANDLING OF ERROR FLAGSMany CSPICE functions bypass the library's own error handling mechanism; instead
they return a status flag, sometimes called "found" or "ok", or perhaps an empty
response to indicate failure. Thecspycemodule provides alternative options
for these functions.Withincspyce, functions that return error flags have an alternative
implementation with a suffix of "_error", which uses the CSPICE/cspyceerror
handling mechanism detailed above instead.Note that most_errorversions of functions have fewer return values than the
associated non-error versions. The user should be certain which version is being
used before interpreting the returned value(s).Thecspycemodule provides several ways to control which version of the
function to use:The functionuse_flags()takes a function name or list of names and
designates the original version of each function as the default. If the input
argument is missing, original versions are selected universally.The functionuse_errors()takes a function name or list of names and
designates the_errorversion of each function as the default. If the input
argument is missing,_errorversions are selected universally.To provide a more consistent Python interface, the_errorversions of allcspycefunctions are selected by default. You can also choose between the
"flag" and "error" versions of a function usingcspycefunction attributes,
as discussed below.VECTORS AND ARRAYSVECTORIZATIONNearly every function that takes floating-point input (be it a
scalar, 1-D array, or 2-D array) has a vectorized version that allows you to
pass a vector of these items in place of a single value. The CSPICE function is
called for each of the provided inputs, the results are collected, and thecspycefunction returns a vector of results.Vectorized versions have the same name but with_vectorappended.In a vectorized function, you can replace any or all floating-point input
parameters with an array having one extra leading dimension. Integer, boolean,
and string inputs cannot be replaced by arrays.If no inputs have an extra dimension, then the result is the same as
calling the original, un-vectorized function.Otherwise, all returned quantities are replaced by arrays having the size of
the largest leading axis.Note that it is permissible to pass arrays with different leading axis sizes
to the function. The vectorized function cycles through the elements of each
array repeatedly if necessary. It may make sense to do this if each leading
axis is an integer fraction of the largest axis size. For example, if the
first input array has size 100 and the second has size 25, then the returned
arrays(s) will have 100 elements and the values of the second will each be
used four times. However, caution is advised when using this capability.Some functions are not vectorized. These include:Functions that have no floating-point inputs.Functions that include strings among the returned quantities.Functions that already return arrays where the leading axis could be
variable in size.In the two cases (ckgpandckgpav) where a function can be both vectorized
and either raise an error or return a flag, the_vectorsuffix comes
before_error.ARRAYSAn optional import allows thecspycemodule to support multidimensional
arrays:importcspyceimportcspyce.arraysThe latter import creates a new function in which the suffix_arrayreplaces_vectorfor every vectorized function. Whereas_vectorfunctions support
only a single extra dimension,_arrayfunctions follow all the standard rules
of shape broadcasting as defined in NumPy. For example, if one input has leading
dimension (10,4) and another has dimension (4,), then the two shapes will be
broadcasted together and returned quantities will be arrays with shape (10,4).You can choose between the scalar, vector, and array versions of a function by
using their explicit names, or by usingcspycefunction attributes, as discussed
below.ALIASESAliases allow the user to associate multiple names or SPICE codes with the same
CSPICE body or frame. Aliases can be used for a variety of purposes.You can use names and codes interchangeably as input arguments to anycspycefunction.You can use a body name or code in place of a frame name or code, and the
primary frame associated with that identified body will be used.Strings that represent integers are equivalent to the integers themselves.Most importantly, you can allow multiple names or codes to refer to the same
CSPICE body or frame. For bodies and frames that have multiple names or codes,
calls to acspycefunction will try each option in sequence until it finds one
that works. Options are always tried in the order in which they were defined, so
higher-priority names and codes are tried first.Example 1: Jupiter's moon Dia uses code 553, but it previously used code
55076. With 55076 defined as an alias for 553, acspycecall will return
information about Dia under either of its codes.Example 2: The Earth's rotation is, by default, modeled by frame "IAU_EARTH".
However, "ITRF93" is the name of a much more precise description of Earth's
rotation. If you define "IAU_EARTH" as an alias for "ITRF93", then thecspycetoolkit will use ITRF93 if it is available, and otherwise IAU_EARTH.Immediately after acspycecall involving aliases, you can find out what value
or values were actually used by looking at attributes of the function. For
example, the first input to thecspycefunctionspkezis calledtargand
it identifies the code of a target being observed. After a call tocspyce.spkez(553,...)the value ofcspyce.spkez.targwill be the code actually used, in this case
either 553 or 55076.To enable aliases, you must import an additional moduleimportcspyceimportcspyce.aliases(Note thatcspyce.aliasesandcspyce.arrayscan both be imported, and in
either order. Note also that these are unconventional modules, in that they
introduce new functionality into thecspycenamespace rather than creating
new namespaces calledcspyce.aliasesandcspyce.arrays.)With this import, a new function is defined for everycspycefunction that takes
a frame or body as input. The new function has the same name as the pre-existingcspycefunction, but with_aliasinserted immediately after the originalcspycename (and before any other suffix such as_vectoror_error).You can make alias support the default for individualcspycefunctions or for
the entirecspycemodule by callingcspyce.use_aliases(). These versions
can subsequently be disabled as the default by callingcspyce.use_noaliases()(see more detailed discussion below).To define a body alias or frame alias, callcspyce.define_body_aliases(name_or_code, name_or_code, ...)
cspyce.define_frame_aliases(name_or_code, name_or_code, ...)where the arguments are an arbitrary list of codes and names.To determine the aliases associated with a name or code, callcspyce.get_body_aliases(name_or_code)
cspyce.get_frame_aliases(name_or_code)where the argument is either a name or a code.You can also select between the alias-supporting and alias-nonsupporting
versions of a function using function attributes as discussed below.FUNCTION NAMES, VERSIONS AND SELECTION METHODSAcspycefunction can accumulate several suffixes, based on the particular
behavior, as so:basename[_alias][_vector|_array][_error]Only functions that are truly distinct are defined. For example, if a function
does not have a vector option, then no function will exist containing the_vectorsuffix.You can use these functions to set defaults:cspyce.use_flags()
cspyce.use_errors()
cspyce.use_scalars()
cspyce.use_vectors()
cspyce.use_arrays()
cspyce.use_aliases()
cspyce.use_noaliases()Each function can take one or more arguments referencing specificcspycefunctions, in which case the defaults only apply to those functions. If no
arguments are specified, the default applies to all functions. For example,
to use "flags" as the default for all functions exceptckgp, you could use:cspyce.use_flags()
cspyce.use_errors(cspyce.ckgp)FUNCTION ATTRIBUTESFunction attributes provide a simpler mechanism for choosing the needed
version of a function, without needing to remember the suffix rules. Everycspycefunction has these attributes, each of which identifies another
(or possibly the same)cspycefunction:AttributeMeaningfunc.flagthe equivalent function without the _error suffix, if any.func.errorthe equivalent function with the _error suffix, if any.func.scalarthe equivalent function without _array or _vector suffixes.func.vectorthe equivalent function with the _vector suffix, if any.func.arraythe equivalent function with the _array suffix, if any.func.aliasthe equivalent function with the _alias suffix, if any.func.noaliasthe equivalent function without the _alias suffix, if any.These attributes are always defined, even if the particular option is not
supported by that function. This saves the programmer the effort of remembering,
for example, which functions support aliases or which functions support flags.Thus, if the programmer wishes to be sure they are using the error version of
functionbodn2c, and wants the vector version if it exists (but it doesn't!),
they can callcspyce.bodn2c.error.vector(args,...)RECORD ENHANCEMENTSSpiceCellcspyceprovides an enhanced version ofSpiceCellto make it simpler to use for
both CSPICE and in Python.In the documentation that follows,active elementsrefer to those elements in theSpiceCellwhoseindexis such that0 ≤ index < spice_cell.card.ConstructorsTo create aSpiceCell:fromcspyceimportSpiceCell,SPICE_CELL_INT,SPICE_CELL_DOUBLEspice_cell=SpiceCell(typeno=SPICE_CELL_INT,size=20)spice_cell=SpiceCell(typeno=SPICE_CELL_DOUBLE,size=10)With these constructors,spice_cell.cardwill be set to 0 and there will initially be
no active elements.If you already have data that you want to convert to a spice cell, you can use a simpler
interface:spice_cell=SpiceCell([1,2,3,4,5])spice_cell=SpiceCell(np.arange(1.0,10.0))spice_cell=SpiceCell(np.arange(1.0,10.0),size=40)# set size explicitlyIf you use these constructions, Python will create aSpiceCellwhose size is a little
bigger than the length of the given data. The passed first argument will be the active
elements.Any CSPICE function that expects aSpiceCellas an input can also be passed an array,
a tuple, or anything that can reasonably be converted into an appropriately typedSpiceCell:Any CSPICE function that returns aSpiceCellas a result takes an optional final
argument.If this argument is omitted, aSpiceCellwith a function-specific default capacity
will be created, and the output will be placed into it.If this argument is aSpiceCell, it will be used as the output argument.If this argument is an integer, aSpiceCellwith that capacity will be created and
used as the output.In all cases, theSpiceCelloutput will also be a return value.>>>importcspyce
>>>cspyce.wninsd(2.0,4.9,(1.0,3.0,5.0,7.0,9.0,11.0))<SpiceCelldouble6/12[1.4.95.7.9.11.]>Sequence-like operationsSpiceCelloffers the following methods so that they behave like Python sequences.spice_cell[index],spice_cell[index] = value:  Gets or sets theindex-th element of theSpiceCell.
Must have-len(spice_cell) ≤ index < spice_cell.size.  As in Python, we allow
negative indices, but -1, -2, etc count backwards from the last active elements.len(spice_cell): Returns the number of active elements ofspice_cell.spice_cell.append(value): Ifvalueis a float or integer, it is added to theSpiceCell's active cells.
Ifvalueis an array, all of its elements are added to theSpiceCell's active cells.
The cell's maximum size is grown if necessary.spice_cell.extend(values): Appends each value invaluesto the end of theSpiceCell's active cells.
Each element ofvaluescan be a float, an integer, or an array.
TheSpiceCell's maximum size is grown if necessary.spice_cell += values: Synonym forspice_cell.extend(values)spice_cell.clear(): Make all elements inactive. Same asspice_cell.card = 0.iter(spice_cell): Iterates through the active elements ofspice_cell.
Because of this iterator,list(spice_cell),set(spice_cell), andtuple(spice_cell)work as expected.
You can also write a for loopfor item in spice_cell: ...to iterate through
the active elements.bool(spice_cell): If aspice_cellis used in a boolean context, its value isFalseif all elements
are inactive (spice.cell.card == 0), andTrueotherwise.SpiceCell-specific operationsSpiceCellalso has the following methods and properties specific to aSpiceCell.spice_cell.size: Gets the current maximum size of theSpiceCell.spice_cell.size = value: Grows or shrinks the maximum size of theSpiceCell.
If the number of active elements is greater thanvalue, it is reduced tovalue.
This operation is acspyceenhancement that does not exist in CSPICE.spice_cell.card: Same aslen(spice_cell).  (Also known as the "cardinality", hence the name).spice_cell.card = value: Changes the number of active elements in theSpiceCell.
Must have0 ≤ value < spice_cell.size.spice_cell.as_array(): Returns a view of the active contents of the array as a numpy arrayspice_cell.as_intervals(): Returns a view of the active contents of the array as a 2-dimensionalcard/2x 2 array.
ManySpiceCells are used to represent intervals in which each
pair of numbers represents the lower and upper bounds.Althoughcspyce'sSpiceCells can grow and shrink, CSPICE is not aware of this
capability. Its functions will still raise a WINDOWOVERFLOW ifSpiceCell.sizeis
not large enough to hold the results.  The user must increaseSpiceCell.sizeand try
again.Handling intervals and other structuresAlthough internally, aSpiceCellis a flat array of integers or floats,
some CSPICE routines treat the contents of aSpiceCellas if it were a 2-dimensional array.
For example, some CSPICE routines expect theSpiceCellto contain pairs of values
where each pair represents the limits of an interval.To simplify dealing with this use case, the methodsappendandextendhave been enhanced.
You can pass an array or an array-like object toappend, and all elements of the
array will be added to theSpiceCell.
Likewise you can passextenda sequence of array-like objects, and all of them will
be added to theSpiceCell.So, for example, you could write:spice_cell.append([10,20])spice_cell.extend([[35,50],[90,100],[120,140]])to add intervals to your SpiceCell.To view aSpiceCellcontaining intervals, you can usespice_cell.as_intervals()as described above.
This is just a shortcut forspice_cell.as_array().reshape(-1, 2), where
-1 is a special marker toreshapesaying "figure out this value from the size of the
array and the other dimensions".
The expressionspice_cell.as_array().reshape(-1, 3)would give an array of triples.self.as_array().reshape(-1, 4, 4)gives an array of 4x4 matrices.