This Jupyter notebook demonstrates using the cdasws Python package to retrieve data from cdaweb in multiple different data models. The data models demonstrated include the SpacePy data model, xarray.Dataset, and Pandas DataFrame. This notebook contains the following sections:
Install the prerequisite software from the Python Package Index.
Execute some preliminary code that is necessary before the code that follows.
from datetime import datetime
from cdasws import CdasWs, TimeInterval
from cdasws.datarepresentation import DataRepresentation as dr
from IPython.core.display import HTML
import matplotlib.pyplot as plt
cdas = CdasWs()
# limit display of long lists
DISP_LIMIT = 5
today = datetime.now().strftime('%Y-%B-%d')
def display_link(
url: str,
text: str) -> None:
display(HTML(f'<a href="{url}" target="_blank">{text}</a>'))
The following code demontrates how to get a list of datasets.
datasets = cdas.get_datasets(observatoryGroup='ACE',
instrumentType='Magnetic Fields (space)')
for index, dataset in enumerate(datasets):
dataset_id = dataset["Id"]
dataset_label = dataset["Label"]
print(f'{index}. {dataset_id}, {dataset_label}')
if 'AC_H3_MFI' in dataset_id: # select this dataset for use below
print('...')
print(f'{len(datasets) - 1}. {datasets[-1]["Id"]}, {datasets[-1]["Label"]}')
break
#print(dataset)
doi = dataset['Doi']
print(f'\nSelected dataset: {dataset_id} (doi:{doi})')
display_link(dataset['Notes'], 'Notes')
display(HTML(f'<b>Data Citation</b>: {cdas.get_citation(doi)}. Accessed on {today}.'))
0. AC_AT_DEF, ACE Hourly RTN, GSE and J2000 GCI Attitude direction cosines - E. C. Stone (California Institute of Technology) 1. AC_H0_MFI, H0 - ACE Magnetic Field 16-Second Level 2 Data - N. Ness (Bartol Research Institute) 2. AC_H1_MFI, H1 - ACE Magnetic Field 4-Minute Level 2 Data - N. Ness (Bartol Research Institute) 3. AC_H2_MFI, H2 - ACE Magnetic Field 1-Hour Level 2 Data - N. Ness (Bartol Research Institute) 4. AC_H3_MFI, H3 - ACE Magnetic Field 1-Second Level 2 Data - N. Ness (Bartol Research Institute) ... 15. OMNI_HRO_5MIN, OMNI Combined, Definitive, 5-minute IMF and Plasma, and Energetic Proton Fluxes, Time-Shifted to the Nose of the Earth's Bow Shock, plus Magnetic Indices - J.H. King, N. Papatashvilli (AdnetSystems, NASA GSFC) Selected dataset: AC_H3_MFI (doi:10.48322/7xyh-4z44)
The following code demonstrates how to get a dataset's variables.
variables = cdas.get_variables(doi)
var_names = []
for index, variable in enumerate(variables):
name = variable['Name']
var_names.append(name)
print(f'{index}. {name}, {variable["LongDescription"]}')
time_interval = TimeInterval('2009-06-01T00:00:00Z', '2009-06-01T00:01:00Z')
0. Magnitude, B-field magnitude 1. BRTN, Magnetic Field Vector in RTN coordinates (1 sec) 2. BGSEc, Magnetic Field Vector in GSE Cartesian coordinates (1 sec) 3. BGSM, Magnetic field vector in GSM coordinates (1 sec)
The following code demonstrates how to access data for a selected time range from the selected dataset. The data is retrieved in the following ways:
You would typically only use one method. You may choose one over the other if you are integrating this code with other code that expects the data to be organized a specific way or if you have a another reason to prefer a specific data model.
The following code demonstrates how to retrieve data into a SpacePy data model.
_, data = cdas.get_data(doi, var_names, time_interval, dataRepresentation = dr.SPACEPY)
print(data)
{'Epoch': VarCopy([datetime.datetime(2009, 6, 1, 0, 0, 0, 100000), datetime.datetime(2009, 6, 1, 0, 0, 1, 100000), datetime.datetime(2009, 6, 1, 0, 0, 2, 100000), datetime.datetime(2009, 6, 1, 0, 0, 3, 100000), datetime.datetime(2009, 6, 1, 0, 0, 4, 100000), datetime.datetime(2009, 6, 1, 0, 0, 5, 100000), datetime.datetime(2009, 6, 1, 0, 0, 6, 100000), datetime.datetime(2009, 6, 1, 0, 0, 7, 100000), datetime.datetime(2009, 6, 1, 0, 0, 8, 100000), datetime.datetime(2009, 6, 1, 0, 0, 9, 100000), datetime.datetime(2009, 6, 1, 0, 0, 10, 100000), datetime.datetime(2009, 6, 1, 0, 0, 11, 100000), datetime.datetime(2009, 6, 1, 0, 0, 12, 100000), datetime.datetime(2009, 6, 1, 0, 0, 13, 100000), datetime.datetime(2009, 6, 1, 0, 0, 14, 100000), datetime.datetime(2009, 6, 1, 0, 0, 15, 100000), datetime.datetime(2009, 6, 1, 0, 0, 16, 100000), datetime.datetime(2009, 6, 1, 0, 0, 17, 100000), datetime.datetime(2009, 6, 1, 0, 0, 18, 100000), datetime.datetime(2009, 6, 1, 0, 0, 19, 100000), datetime.datetime(2009, 6, 1, 0, 0, 20, 100000), datetime.datetime(2009, 6, 1, 0, 0, 21, 100000), datetime.datetime(2009, 6, 1, 0, 0, 22, 100000), datetime.datetime(2009, 6, 1, 0, 0, 23, 100000), datetime.datetime(2009, 6, 1, 0, 0, 24, 100000), datetime.datetime(2009, 6, 1, 0, 0, 25, 100000), datetime.datetime(2009, 6, 1, 0, 0, 26, 100000), datetime.datetime(2009, 6, 1, 0, 0, 27, 100000), datetime.datetime(2009, 6, 1, 0, 0, 28, 100000), datetime.datetime(2009, 6, 1, 0, 0, 29, 100000), datetime.datetime(2009, 6, 1, 0, 0, 30, 100000), datetime.datetime(2009, 6, 1, 0, 0, 31, 100000), datetime.datetime(2009, 6, 1, 0, 0, 32, 100000), datetime.datetime(2009, 6, 1, 0, 0, 33, 100000), datetime.datetime(2009, 6, 1, 0, 0, 34, 100000), datetime.datetime(2009, 6, 1, 0, 0, 35, 100000), datetime.datetime(2009, 6, 1, 0, 0, 36, 100000), datetime.datetime(2009, 6, 1, 0, 0, 37, 100000), datetime.datetime(2009, 6, 1, 0, 0, 38, 100000), datetime.datetime(2009, 6, 1, 0, 0, 39, 100000), datetime.datetime(2009, 6, 1, 0, 0, 40, 100000), datetime.datetime(2009, 6, 1, 0, 0, 41, 100000), datetime.datetime(2009, 6, 1, 0, 0, 42, 100000), datetime.datetime(2009, 6, 1, 0, 0, 43, 100000), datetime.datetime(2009, 6, 1, 0, 0, 44, 100000), datetime.datetime(2009, 6, 1, 0, 0, 45, 100000), datetime.datetime(2009, 6, 1, 0, 0, 46, 100000), datetime.datetime(2009, 6, 1, 0, 0, 47, 100000), datetime.datetime(2009, 6, 1, 0, 0, 48, 100000), datetime.datetime(2009, 6, 1, 0, 0, 49, 100000), datetime.datetime(2009, 6, 1, 0, 0, 50, 100000), datetime.datetime(2009, 6, 1, 0, 0, 51, 100000), datetime.datetime(2009, 6, 1, 0, 0, 52, 100000), datetime.datetime(2009, 6, 1, 0, 0, 53, 100000), datetime.datetime(2009, 6, 1, 0, 0, 54, 100000), datetime.datetime(2009, 6, 1, 0, 0, 55, 100000), datetime.datetime(2009, 6, 1, 0, 0, 56, 100000), datetime.datetime(2009, 6, 1, 0, 0, 57, 100000), datetime.datetime(2009, 6, 1, 0, 0, 58, 100000), datetime.datetime(2009, 6, 1, 0, 0, 59, 100000)], dtype=object), 'Magnitude': VarCopy([3.526, 3.578, 3.592, 3.563, 3.533, 3.49 , 3.459, 3.365, 3.377, 3.401, 3.463, 3.492, 3.59 , 3.573, 3.567, 3.541, 3.518, 3.497, 3.443, 3.415, 3.388, 3.395, 3.43 , 3.482, 3.538, 3.522, 3.545, 3.562, 3.5 , 3.44 , 3.401, 3.355, 3.371, 3.404, 3.44 , 3.504, 3.586, 3.647, 3.535, 3.518, 3.596, 3.565, 3.529, 3.44 , 3.368, 3.401, 3.491, 3.51 , 3.518, 3.581, 3.589, 3.514, 3.562, 3.503, 3.448, 3.405, 3.374, 3.373, 3.395, 3.451], dtype=float32), 'BRTN': VarCopy([[ 0.339, -2.066, -2.837], [ 0.16 , -2.148, -2.856], [ 0.302, -2.273, -2.764], [ 0.349, -2.264, -2.729], [ 0.31 , -2.241, -2.713], [ 0.251, -2.221, -2.681], [ 0.244, -2.18 , -2.675], [ 0.269, -2.104, -2.611], [ 0.263, -2.083, -2.645], [ 0.164, -2.071, -2.692], [ 0.14 , -2.087, -2.76 ], [ 0.166, -2.075, -2.804], [ 0.212, -2.161, -2.859], [ 0.251, -2.199, -2.805], [ 0.233, -2.244, -2.762], [ 0.239, -2.26 , -2.716], [ 0.373, -2.263, -2.667], [ 0.379, -2.223, -2.673], [ 0.289, -2.217, -2.618], [ 0.327, -2.135, -2.646], [ 0.385, -2.08 , -2.646], [ 0.424, -2.087, -2.644], [ 0.382, -2.096, -2.688], [ 0.431, -2.023, -2.8 ], [ 0.488, -2.053, -2.84 ], [ 0.345, -2.073, -2.826], [ 0.382, -2.116, -2.818], [ 0.387, -2.212, -2.764], [ 0.368, -2.197, -2.699], [ 0.407, -2.172, -2.636], [ 0.445, -2.119, -2.622], [ 0.422, -2.049, -2.624], [ 0.407, -2.013, -2.673], [ 0.484, -1.998, -2.713], [ 0.428, -2.023, -2.749], [ 0.452, -2.04 , -2.812], [ 0.672, -2.071, -2.849], [ 0.603, -2.197, -2.847], [ 0.304, -2.369, -2.603], [-0.294, -2.573, -2.376], [-0.382, -2.641, -2.409], [-0.428, -2.594, -2.407], [-0.433, -2.501, -2.452], [-0.485, -2.334, -2.479], [-0.361, -2.333, -2.401], [-0.208, -2.269, -2.524], [-0.02 , -2.152, -2.742], [ 0.02 , -1.946, -2.92 ], [-0.203, -2.113, -2.803], [-0.336, -2.336, -2.692], [-0.155, -2.39 , -2.673], [-0.18 , -2.366, -2.591], [-0.241, -2.44 , -2.585], [-0.263, -2.344, -2.589], [-0.219, -2.344, -2.519], [-0.18 , -2.269, -2.532], [-0.105, -2.181, -2.572], [-0.011, -2.086, -2.651], [ 0.071, -2.092, -2.673], [ 0.034, -2.313, -2.56 ]], dtype=float32), 'BGSEc': VarCopy([[-0.342, 2.406, -2.555], [-0.164, 2.49 , -2.563], [-0.306, 2.602, -2.457], [-0.352, 2.588, -2.422], [-0.313, 2.564, -2.41 ], [-0.254, 2.54 , -2.38 ], [-0.247, 2.498, -2.38 ], [-0.273, 2.415, -2.326], [-0.266, 2.399, -2.362], [-0.167, 2.393, -2.41 ], [-0.143, 2.417, -2.476], [-0.17 , 2.411, -2.521], [-0.216, 2.503, -2.565], [-0.255, 2.534, -2.506], [-0.237, 2.573, -2.458], [-0.242, 2.583, -2.41 ], [-0.377, 2.58 , -2.361], [-0.382, 2.541, -2.372], [-0.292, 2.528, -2.318], [-0.331, 2.45 , -2.357], [-0.388, 2.395, -2.363], [-0.428, 2.402, -2.36 ], [-0.386, 2.417, -2.403], [-0.434, 2.359, -2.524], [-0.492, 2.393, -2.559], [-0.348, 2.411, -2.542], [-0.385, 2.453, -2.53 ], [-0.39 , 2.542, -2.464], [-0.371, 2.518, -2.401], [-0.411, 2.486, -2.342], [-0.448, 2.431, -2.335], [-0.425, 2.362, -2.345], [-0.41 , 2.332, -2.399], [-0.487, 2.323, -2.44 ], [-0.431, 2.352, -2.473], [-0.456, 2.376, -2.533], [-0.675, 2.412, -2.566], [-0.606, 2.537, -2.548], [-0.308, 2.677, -2.284], [ 0.29 , 2.852, -2.034], [ 0.379, 2.923, -2.058], [ 0.425, 2.876, -2.062], [ 0.429, 2.79 , -2.118], [ 0.482, 2.628, -2.166], [ 0.358, 2.616, -2.089], [ 0.205, 2.568, -2.219], [ 0.017, 2.48 , -2.45 ], [-0.023, 2.297, -2.653], [ 0.2 , 2.449, -2.516], [ 0.332, 2.656, -2.377], [ 0.152, 2.707, -2.351], [ 0.177, 2.673, -2.273], [ 0.238, 2.745, -2.258], [ 0.26 , 2.651, -2.274], [ 0.216, 2.643, -2.204], [ 0.176, 2.57 , -2.227], [ 0.101, 2.487, -2.278], [ 0.008, 2.403, -2.367], [-0.074, 2.411, -2.389], [-0.038, 2.616, -2.249]], dtype=float32), 'BGSM': VarCopy([[-0.342, 3.083, -1.676], [-0.164, 3.166, -1.658], [-0.306, 3.239, -1.522], [-0.352, 3.215, -1.493], [-0.313, 3.188, -1.489], [-0.254, 3.156, -1.469], [-0.247, 3.116, -1.481], [-0.273, 3.021, -1.456], [-0.266, 3.016, -1.495], [-0.167, 3.026, -1.543], [-0.143, 3.069, -1.598], [-0.17 , 3.077, -1.642], [-0.216, 3.178, -1.656], [-0.255, 3.19 , -1.59 ], [-0.237, 3.212, -1.532], [-0.242, 3.206, -1.484], [-0.377, 3.188, -1.438], [-0.382, 3.154, -1.461], [-0.292, 3.125, -1.414], [-0.331, 3.063, -1.474], [-0.388, 3.013, -1.498], [-0.428, 3.019, -1.493], [-0.386, 3.046, -1.529], [-0.434, 3.029, -1.662], [-0.492, 3.072, -1.684], [-0.348, 3.084, -1.663], [-0.385, 3.12 , -1.638], [-0.39 , 3.183, -1.548], [-0.371, 3.142, -1.496], [-0.411, 3.092, -1.45 ], [-0.448, 3.039, -1.46 ], [-0.425, 2.975, -1.491], [-0.41 , 2.964, -1.552], [-0.487, 2.968, -1.594], [-0.431, 3.006, -1.616], [-0.456, 3.048, -1.665], [-0.675, 3.092, -1.685], [-0.606, 3.205, -1.63 ], [-0.308, 3.256, -1.335], [ 0.29 , 3.344, -1.043], [ 0.379, 3.42 , -1.044], [ 0.425, 3.376, -1.062], [ 0.429, 3.311, -1.142], [ 0.482, 3.172, -1.239], [ 0.358, 3.137, -1.168], [ 0.205, 3.132, -1.307], [ 0.017, 3.12 , -1.554], [-0.023, 3.01 , -1.804], [ 0.2 , 3.112, -1.626], [ 0.332, 3.265, -1.43 ], [ 0.152, 3.305, -1.39 ], [ 0.177, 3.249, -1.326], [ 0.238, 3.312, -1.289], [ 0.26 , 3.228, -1.334], [ 0.216, 3.198, -1.27 ], [ 0.176, 3.136, -1.314], [ 0.101, 3.073, -1.388], [ 0.008, 3.021, -1.5 ], [-0.074, 3.036, -1.518], [-0.038, 3.187, -1.321]], dtype=float32), 'cartesian': VarCopy(['x_component', 'y_component', 'z_component'], dtype='<U11'), 'metavar0': VarCopy(['Br RTN', 'Bt RTN', 'Bn RTN'], dtype='<U6'), 'metavar1': VarCopy(['Bx GSE', 'By GSE', 'Bz GSE'], dtype='<U6'), 'metavar2': VarCopy(['Bx (GSM)', 'By (GSM)', 'Bz (GSM)'], dtype='<U8')}
The following code displays metadata for the Magnitude variable from the spacepy data model.
print(data[var_names[0]].attrs)
{'FIELDNAM': 'B-field magnitude', 'VALIDMIN': np.float32(0.0), 'VALIDMAX': np.float32(500.0), 'SCALEMIN': np.float32(0.0), 'SCALEMAX': np.float32(10.0), 'UNITS': 'nT', 'FORMAT': 'F8.3', 'VAR_TYPE': 'data', 'DICT_KEY': 'magnetic_field>magnitude', 'FILLVAL': np.float32(-1e+31), 'DEPEND_0': 'Epoch', 'CATDESC': 'B-field magnitude', 'LABLAXIS': '<|B|>', 'DISPLAY_TYPE': 'time_series', 'DIM_SIZES': np.int32(0)}
The following code plots the Magnitude
variable's values using the label values from the spacepy data model.
fig = data.plot([var_names[0]])
/home/btharris/opt/python/39/jupyter/lib64/python3.9/site-packages/spacepy/empiricals.py:26: UserWarning: Qin-Denton/OMNI2 data not found in current format. This module has limited functionality. Run spacepy.toolbox.update(QDomni=True) to download data. import spacepy.omni as om
The following code demonstrates how to retrieve data into an xarray.Dataset.
_, data = cdas.get_data(doi, var_names, time_interval, dataRepresentation = dr.XARRAY)
print(data)
<xarray.Dataset> Size: 3kB Dimensions: (Epoch: 60, cartesian: 3) Coordinates: * Epoch (Epoch) datetime64[ns] 480B 2009-06-01T00:00:00.100000 ... 200... * cartesian (cartesian) <U11 132B 'x_component' 'y_component' 'z_component' metavar0 (cartesian) <U6 72B 'Br RTN' 'Bt RTN' 'Bn RTN' metavar1 (cartesian) <U6 72B 'Bx GSE' 'By GSE' 'Bz GSE' metavar2 (cartesian) <U8 96B 'Bx (GSM)' 'By (GSM)' 'Bz (GSM)' Data variables: Magnitude (Epoch) float32 240B 3.526 3.578 3.592 ... 3.373 3.395 3.451 BRTN (Epoch, cartesian) float32 720B 0.339 -2.066 ... -2.313 -2.56 BGSEc (Epoch, cartesian) float32 720B -0.342 2.406 ... 2.616 -2.249 BGSM (Epoch, cartesian) float32 720B -0.342 3.083 ... 3.187 -1.321 Attributes: (12/29) TITLE: ['ACE> Magnetometer Parameters'] Project: ['ACE>Advanced Composition Explorer', 'ISTP>... Discipline: ['Space Physics>Interplanetary Studies'] Source_name: ['AC>Advanced Composition Explorer'] Data_type: ['H3>1-Sec Level 2 Data'] Descriptor: ['MAG>ACE Magnetic Field Instrument'] ... ... Web_site: ['http://www.srl.caltech.edu/ACE/'] Acknowledgement: ['Please acknowledge the Principal', 'Invest... Rules_of_use: ['See the rules of use available from the AC... spase_DatasetResourceID: ['spase://NASA/NumericalData/ACE/MAG/L2/PT1S'] DOI: ['https://doi.org/10.48322/7xyh-4z44'] CDAWEB_PARENTS: ['ac_h3_mfi_00000000_v01', 'ac_h3_mfi_200906...
The following code displays metadata for the Magnitude
variable from the xarray.Dataset
.
print(data[var_names[0]])
<xarray.DataArray 'Magnitude' (Epoch: 60)> Size: 240B array([3.526, 3.578, 3.592, 3.563, 3.533, 3.49 , 3.459, 3.365, 3.377, 3.401, 3.463, 3.492, 3.59 , 3.573, 3.567, 3.541, 3.518, 3.497, 3.443, 3.415, 3.388, 3.395, 3.43 , 3.482, 3.538, 3.522, 3.545, 3.562, 3.5 , 3.44 , 3.401, 3.355, 3.371, 3.404, 3.44 , 3.504, 3.586, 3.647, 3.535, 3.518, 3.596, 3.565, 3.529, 3.44 , 3.368, 3.401, 3.491, 3.51 , 3.518, 3.581, 3.589, 3.514, 3.562, 3.503, 3.448, 3.405, 3.374, 3.373, 3.395, 3.451], dtype=float32) Coordinates: * Epoch (Epoch) datetime64[ns] 480B 2009-06-01T00:00:00.100000 ... 2009-... Attributes: (12/18) FIELDNAM: B-field magnitude VALIDMIN: 0.0 VALIDMAX: 500.0 SCALEMIN: 0.0 SCALEMAX: 10.0 UNITS: nT ... ... LABLAXIS: <|B|> DISPLAY_TYPE: time_series DIM_SIZES: 0 standard_name: B-field magnitude units: nT long_name: <|B|>
The following code plots the Magnitude
variable's values using the label values from the xarray.Dataset
.
data[var_names[0]].plot()
plt.show()
df = data[var_names[0]].to_dataframe()
print(df)
Magnitude Epoch 2009-06-01 00:00:00.100 3.526 2009-06-01 00:00:01.100 3.578 2009-06-01 00:00:02.100 3.592 2009-06-01 00:00:03.100 3.563 2009-06-01 00:00:04.100 3.533 2009-06-01 00:00:05.100 3.490 2009-06-01 00:00:06.100 3.459 2009-06-01 00:00:07.100 3.365 2009-06-01 00:00:08.100 3.377 2009-06-01 00:00:09.100 3.401 2009-06-01 00:00:10.100 3.463 2009-06-01 00:00:11.100 3.492 2009-06-01 00:00:12.100 3.590 2009-06-01 00:00:13.100 3.573 2009-06-01 00:00:14.100 3.567 2009-06-01 00:00:15.100 3.541 2009-06-01 00:00:16.100 3.518 2009-06-01 00:00:17.100 3.497 2009-06-01 00:00:18.100 3.443 2009-06-01 00:00:19.100 3.415 2009-06-01 00:00:20.100 3.388 2009-06-01 00:00:21.100 3.395 2009-06-01 00:00:22.100 3.430 2009-06-01 00:00:23.100 3.482 2009-06-01 00:00:24.100 3.538 2009-06-01 00:00:25.100 3.522 2009-06-01 00:00:26.100 3.545 2009-06-01 00:00:27.100 3.562 2009-06-01 00:00:28.100 3.500 2009-06-01 00:00:29.100 3.440 2009-06-01 00:00:30.100 3.401 2009-06-01 00:00:31.100 3.355 2009-06-01 00:00:32.100 3.371 2009-06-01 00:00:33.100 3.404 2009-06-01 00:00:34.100 3.440 2009-06-01 00:00:35.100 3.504 2009-06-01 00:00:36.100 3.586 2009-06-01 00:00:37.100 3.647 2009-06-01 00:00:38.100 3.535 2009-06-01 00:00:39.100 3.518 2009-06-01 00:00:40.100 3.596 2009-06-01 00:00:41.100 3.565 2009-06-01 00:00:42.100 3.529 2009-06-01 00:00:43.100 3.440 2009-06-01 00:00:44.100 3.368 2009-06-01 00:00:45.100 3.401 2009-06-01 00:00:46.100 3.491 2009-06-01 00:00:47.100 3.510 2009-06-01 00:00:48.100 3.518 2009-06-01 00:00:49.100 3.581 2009-06-01 00:00:50.100 3.589 2009-06-01 00:00:51.100 3.514 2009-06-01 00:00:52.100 3.562 2009-06-01 00:00:53.100 3.503 2009-06-01 00:00:54.100 3.448 2009-06-01 00:00:55.100 3.405 2009-06-01 00:00:56.100 3.374 2009-06-01 00:00:57.100 3.373 2009-06-01 00:00:58.100 3.395 2009-06-01 00:00:59.100 3.451
The following code displays the global attributes metadata for the DataFrame.
print(df.attrs)
{}
The following code plots the DataFrame's
values.
df.plot()
plt.show()
View the cdasws API for additional functions. Additional notebook examples are also available.