Imports
Imports¶
import act
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt
import matplotlib.colors as colors
Downloading and Reading ARM’s NetCDF Data¶
ARM’s standard file format is NetCDF (network Common Data Form) which makes it very easy to work with in Python! ARM data are available through a data portal called Data Discovery or through a webservice. If you didn’t get your username and token earlier, please go back and see the Prerequisites!
# Set your username and token here!
username = 'X'
token = 'X'
# Set the datastream and start/enddates
datastream = 'bnfsebsS20.b1'
startdate = '2025-03-31'
enddate = '2025-04-30T23:59:59'
# Use ACT to easily download the data. Watch for the data citation! Show some support
# for ARM's instrument experts and cite their data if you use it in a publication
result_sebs = act.discovery.download_arm_data(username, token, datastream, startdate, enddate)
[DOWNLOADING] bnfsebsS20.b1.20250401.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250424.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250430.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250422.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250429.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250427.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250417.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250418.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250425.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250411.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250420.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250410.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250421.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250403.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250404.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250331.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250402.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250405.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250423.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250414.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250428.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250412.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250407.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250413.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250409.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250406.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250416.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250419.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250415.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250426.000000.cdf
[DOWNLOADING] bnfsebsS20.b1.20250408.000000.cdf
If you use these data to prepare a publication, please cite:
Sullivan, R., Keeler, E., Pal, S., & Kyrouac, J. Surface Energy Balance System
(SEBS), 2025-03-31 to 2025-04-30, Bankhead National Forest, AL, USA; Long-term
Mobile Facility (BNF), Bankhead National Forest, AL, Supplemental facility at
Courtland (S20). Atmospheric Radiation Measurement (ARM) User Facility.
https://doi.org/10.5439/1984921
Note: Did you notice the citation and DOI?¶
# Let's read in the data using ACT and check out the data
ds_sebs = act.io.read_arm_netcdf(result_sebs)
ds_sebs
Quality Controlling Data¶
ARM has multiple methods that it uses to communicate data quality information out to the users. One of these methods is through “embedded QC” variables. These are variables within the file that have information on automated tests that have been applied. Many times, they include Min, Max, and Delta tests but as is the case with the AOS instruments, there can be more complicated tests that are applied.
The results from all these different tests are stored in a single variable using bit-packed QC. We won’t get into the full details here, but it’s a way to communicate the results of multiple tests in a single integer value by utilizing binary and bits! You can learn more about bit-packed QC here but ACT also has many of the tools for working with ARM QC.
Other Sources of Quality Control¶
ARM also communicates problems with the data quality through Data Quality Reports (DQR). These reports are normally submitted by the instrument mentor when there’s been a problem with the instrument. The categories include:
- Data Quality Report Categories
- Missing: Data are not available or set to -9999
- Suspect: The data are not fully incorrect but there are problems that increases the uncertainty of the values. Data should be used with caution.
- Bad: The data are incorrect and should not be used.
- Note: Data notes are a way to communicate information that would be useful to the end user but does not rise to the level of suspect or bad data
Additionally, data quality information can be found in the Instrument Handbooks, which are included on most instrument pages. Here is an example of the MET handbook.
ds_sebs.clean.cleanup()
variable = 'soil_temp_1'
display = act.plotting.TimeSeriesDisplay({'SEBS': ds_sebs}, figsize=(15, 10), subplot_shape=(2,))
display.plot(variable, dsname='SEBS')
display.qc_flag_block_plot(variable, subplot_index=(1,))
<Axes: >

display = act.plotting.TimeSeriesDisplay(ds_sebs, figsize=(20, 10), subplot_shape=(1,))
# Plot up variables in the first plot
display.plot('soil_temp_1', subplot_index=(0,))
display.plot('soil_temp_2', subplot_index=(0,))
display.plot('soil_temp_3', subplot_index=(0,))
# display.qc_flag_block_plot(variable, subplot_index=(1,))
# display.qc_flag_block_plot('soil_temp_2', subplot_index=(2,))
# display.qc_flag_block_plot('soil_temp_3', subplot_index=(3,))
# Plot up a day/night background
display.day_night_background(subplot_index=(0,))
plt.show()

display = act.plotting.TimeSeriesDisplay(ds_sebs, figsize=(20, 10), subplot_shape=(1,))
# Plot up variables in the first plot
display.plot('soil_moisture_1', subplot_index=(0,))
display.plot('soil_moisture_2', subplot_index=(0,))
display.plot('soil_moisture_3', subplot_index=(0,))
# display.qc_flag_block_plot('soil_moisture_1', subplot_index=(1,))
# display.qc_flag_block_plot('soil_moisture_2', subplot_index=(2,))
# display.qc_flag_block_plot('soil_moisture_3', subplot_index=(3,))
# Plot up a day/night background
display.day_night_background(subplot_index=(0,))
plt.show()
# Correlation with MET dataset tbrg_precip_total_corr

list(ds_sebs.variables)
['base_time',
'time_offset',
'time_bounds',
'down_short_hemisp',
'qc_down_short_hemisp',
'up_short_hemisp',
'qc_up_short_hemisp',
'down_long',
'qc_down_long',
'up_long',
'qc_up_long',
'surface_soil_heat_flux_1',
'qc_surface_soil_heat_flux_1',
'surface_soil_heat_flux_2',
'qc_surface_soil_heat_flux_2',
'surface_soil_heat_flux_3',
'qc_surface_soil_heat_flux_3',
'soil_moisture_1',
'qc_soil_moisture_1',
'soil_moisture_2',
'qc_soil_moisture_2',
'soil_moisture_3',
'qc_soil_moisture_3',
'soil_temp_1',
'qc_soil_temp_1',
'soil_temp_2',
'qc_soil_temp_2',
'soil_temp_3',
'qc_soil_temp_3',
'soil_heat_flow_1',
'qc_soil_heat_flow_1',
'soil_heat_flow_2',
'qc_soil_heat_flow_2',
'soil_heat_flow_3',
'qc_soil_heat_flow_3',
'corr_soil_heat_flow_1',
'qc_corr_soil_heat_flow_1',
'corr_soil_heat_flow_2',
'qc_corr_soil_heat_flow_2',
'corr_soil_heat_flow_3',
'qc_corr_soil_heat_flow_3',
'soil_heat_capacity_1',
'qc_soil_heat_capacity_1',
'soil_heat_capacity_2',
'qc_soil_heat_capacity_2',
'soil_heat_capacity_3',
'qc_soil_heat_capacity_3',
'energy_storage_change_1',
'qc_energy_storage_change_1',
'energy_storage_change_2',
'qc_energy_storage_change_2',
'energy_storage_change_3',
'qc_energy_storage_change_3',
'albedo',
'qc_albedo',
'net_radiation',
'qc_net_radiation',
'surface_soil_heat_flux_avg',
'qc_surface_soil_heat_flux_avg',
'surface_energy_balance',
'qc_surface_energy_balance',
'wetness',
'qc_wetness',
'temp_net_radiometer',
'qc_temp_net_radiometer',
'battery_voltage',
'qc_battery_voltage',
'lat',
'lon',
'alt',
'time']
display = act.plotting.TimeSeriesDisplay(ds_sebs, figsize=(20, 10), subplot_shape=(1,))
# Plot up variables in the first plot
display.plot('surface_soil_heat_flux_1', subplot_index=(0,))
display.plot('surface_soil_heat_flux_2', subplot_index=(0,))
display.plot('surface_soil_heat_flux_3', subplot_index=(0,))
# display.qc_flag_block_plot('surface_soil_heat_flux_1', subplot_index=(1,))
# display.qc_flag_block_plot('surface_soil_heat_flux_2', subplot_index=(2,))
# display.qc_flag_block_plot('surface_soil_heat_flux_3', subplot_index=(3,))
# Plot up a day/night background
display.day_night_background(subplot_index=(0,))
plt.show()

display = act.plotting.TimeSeriesDisplay(ds_sebs, figsize=(20, 10), subplot_shape=(1,))
# Plot up variables in the first plot
display.plot('surface_soil_heat_flux_1', subplot_index=(0,), label='Soil Heat Flux')
display.plot('soil_heat_flow_1', subplot_index=(0,), label='Soil Heat Flow')
# display.qc_flag_block_plot('surface_soil_heat_flux_1', subplot_index=(1,))
# display.qc_flag_block_plot('surface_soil_heat_flux_2', subplot_index=(2,))
# display.qc_flag_block_plot('surface_soil_heat_flux_3', subplot_index=(3,))
# Plot up a day/night background
display.day_night_background(subplot_index=(0,))
plt.legend()
plt.show()

display = act.plotting.TimeSeriesDisplay(ds_sebs, figsize=(20, 10), subplot_shape=(1,))
# Plot up variables in the first plot
display.plot('soil_heat_capacity_1', subplot_index=(0,), label='Soil Heat Capacity')
# display.qc_flag_block_plot('surface_soil_heat_flux_1', subplot_index=(1,))
# display.qc_flag_block_plot('surface_soil_heat_flux_2', subplot_index=(2,))
# display.qc_flag_block_plot('surface_soil_heat_flux_3', subplot_index=(3,))
# Plot up a day/night background
display.day_night_background(subplot_index=(0,))
plt.legend()
plt.show()
