Skip to main content

BET - Brunauer-Emmett-Teller

Brunauer-Emmett-Teller (BET) analysis is used to measure the specific surface area, pore volume, and pore size distribution of solid materials via gas adsorption. It provides key physical properties related to material reactivity and processing behavior.

Method Overview

PropertyValue
Full NameBrunauer-Emmett-Teller Surface Area Analysis
PurposeMeasures surface area, pore volume, and pore size distribution
Adsorptive GasNitrogen (N2) at 77K
SharePoint LocationAnalytical Data > BET
File FormatCSV (instrument export)

Key Metrics

MetricUnitsDescription
AS(BET)m²/gSpecific surface area via BET method
AS(BETMP)m²/gMulti-point BET surface area
Total Pore Volumecm³/gTotal pore volume at specified p/p0
Average Pore DiameternmAverage pore diameter
C-ValuedimensionlessBET constant (adsorption energy indicator)

Pore Size Classification

ClassificationDiameter Range
Micropores< 2 nm
Mesopores2-50 nm
Macropores> 50 nm

Data Pipeline

SharePoint Sources

TypeSiteFoldersFiles
BET DataAnalytical DataBET, BET Data.csv

File naming pattern: {sample_id} - BET Data Output.csv

Dagster Assets

The BET data pipeline consists of the following assets in apps/datasmart/src/datasmart/assets/analytical/bet.py:

bet_tables (sharepoint_multi_asset)
├── bet_params_incremental (backend.bet_params_incremental)
└── bet_raw (analytical.bet_raw)

bet (analytical.bet)

bet_simplified (analytical.bet_simplified)

Asset Descriptions

AssetSchemaDescription
bet_params_incrementalbackendMelted parameter data from CSV files
bet_rawanalyticalRaw isotherm data points
betanalyticalWide format, 1 row per sample with all parameters
bet_simplifiedanalyticalKey metrics only, C > 0 filtered, replicates averaged

Database Tables

analytical.bet_raw

Raw isotherm data points from BET measurements.

ColumnTypeDescription
sample_idstringNormalized sample ID
original_sample_idstringRaw sample ID from filename
NointegerData point number
p/p0floatRelative pressure
p/Va(p0-p)floatBET transform value
file_idstringSharePoint file identifier

analytical.bet

Wide format table with all BET parameters.

ColumnTypeDescription
sample_idstringNormalized sample ID
original_sample_idstringRaw sample ID
analysis_datedatetimeDate of analysis
operatorstringOperator who performed analysis
as(bet)floatBET surface area (m²/g)
as(betmp)floatMulti-point BET surface area (m²/g)
cfloatBET C constant
total_pore_volumefloatTotal pore volume (cm³/g)
average_pore_diameterfloatAverage pore diameter (nm)
p/p0floatRelative pressure for pore calculation
instrumentstringInstrument name
s/nstringSerial number
analysis_portstringAnalysis port used
sample_massfloatSample mass (g)
adsorptivestringAdsorptive gas type
adsorption_data_point_numberintegerNumber of adsorption points
desorption_data_point_numberintegerNumber of desorption points

analytical.bet_simplified

Simplified table with key metrics only.

ColumnTypeDescription
sample_idstringNormalized sample ID
as(bet)floatBET surface area (m²/g)
total_pore_volumefloatTotal pore volume (cm³/g)
average_pore_diameterfloatAverage pore diameter (nm)
p/p0floatRelative pressure

File Format

CSV Structure

BET CSV files contain two sections:

  1. Parameters section: Key-value pairs with parameter, value, and units columns
  2. Raw data section: Isotherm data starting with "No" header

Example structure:

Instrument,BELSorp Mini II,
S/N,xxxxx,
Analysis date,2024-01-15,
Operator,John Doe,
Sample mass,0.1234,g
...
AS(BET),12.345,m²/g
Total pore volume at p/p0=0.99,0.0567,cm³/g
C,89.12,
...
No,p/p0,p/Va(p0-p)
1,0.05,0.123
2,0.10,0.234
...

C-Value Validation

The BET C constant indicates the validity of the measurement:

C ValueInterpretation
C > 0Valid measurement
C < 0Poor fit, non-ideal adsorption
Very large CPotential issues with measurement

The bet_simplified asset automatically filters for measurements where C > 0.

Usage Examples

Query Simplified Data

from shared.db.sql import SQL

# Get simplified BET data (recommended for most analyses)
bet = SQL.read("""
SELECT sample_id, "as(bet)", total_pore_volume, average_pore_diameter
FROM analytical.bet_simplified
WHERE sample_id LIKE 'P800%'
""")

Query Full BET Data

# Get full BET data with all parameters
full_bet = SQL.read("""
SELECT sample_id, original_sample_id, analysis_date, operator,
"as(bet)", c, total_pore_volume, average_pore_diameter,
instrument, sample_mass
FROM analytical.bet
WHERE sample_id IS NOT NULL
ORDER BY analysis_date DESC
""")

Query Isotherm Data

# Get raw isotherm data for plotting
isotherm = SQL.read("""
SELECT "No", "p/p0", "p/Va(p0-p)"
FROM analytical.bet_raw
WHERE sample_id = 'P800-001-1-QBND-FM'
ORDER BY "No"
""")

Plot BET Isotherm

import matplotlib.pyplot as plt

isotherm = SQL.read("""
SELECT "p/p0", "p/Va(p0-p)"
FROM analytical.bet_raw
WHERE sample_id = 'P800-001-1-QBND-FM'
ORDER BY "No"
""")

plt.figure(figsize=(10, 6))
plt.plot(isotherm["p/p0"], isotherm["p/Va(p0-p)"], 'o-')
plt.xlabel("Relative Pressure (p/p0)")
plt.ylabel("p/Va(p0-p)")
plt.title("BET Isotherm")
plt.grid(True, alpha=0.3)
plt.show()

Join with XRF Data

# Combine BET with XRF for material characterization
combined = SQL.read("""
SELECT
b.sample_id,
b."as(bet)" as surface_area,
b.total_pore_volume,
b.average_pore_diameter,
x.CaO, x.MgO, x.SiO2
FROM analytical.bet_simplified b
LEFT JOIN analytical.xrf_simplified x
ON b.sample_id = x.sample_id
WHERE b.sample_id IS NOT NULL
""")

Sample ID Processing

The pipeline uses the SampleID class to normalize sample identifiers:

from data_infrastructure.sample_id import SampleID

# Normalize sample IDs
df = SampleID.update_sample_id(
df,
is_material=True,
project_team_map=project_team_map,
crosswalk=sample_id_crosswalk,
)
AssetDescription
sample_id_crosswalkMaps messy sample IDs to canonical format
project_team_mapMaps old process area codes to new project team codes

Troubleshooting

Missing Samples

If a sample is missing from BET tables:

  1. Check if the source CSV exists in SharePoint under BET/BET Data/
  2. Verify the file naming follows {sample_id} - BET Data Output.csv
  3. Check backend.bet_params_incremental for raw data

Invalid C Values

If samples are missing from bet_simplified:

  1. Check the c value in analytical.bet - must be > 0
  2. Negative or zero C values indicate measurement issues
  3. Contact the analytical team for re-measurement if needed
# Find samples filtered out due to C value
SQL.read("""
SELECT sample_id, "as(bet)", c
FROM analytical.bet
WHERE c <= 0
""")

Sample ID Normalization Issues

If sample IDs aren't matching:

  1. Check original_sample_id column for the raw value
  2. Review sample_id_crosswalk for applicable mappings
  3. Update crosswalk if a new mapping is needed