Skip to article frontmatterSkip to article content

Imports

Authors
Affiliations
Arizona State University
Brookhaven National Laboratory
Cornell University
Colorado State University
Clemson University
Texas Tech University
Lawrence Berkeley National Laboratory
Argonne National Laboratory

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
Loading...

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: >
<Figure size 1500x1000 with 2 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()
<Figure size 2000x1000 with 1 Axes>
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
<Figure size 2000x1000 with 1 Axes>
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()
<Figure size 2000x1000 with 1 Axes>
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()
<Figure size 2000x1000 with 1 Axes>
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()
<Figure size 2000x1000 with 1 Axes>