Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DBFT: critical pavement strains directly from an FWD deflection basin

This repository is the supplementary material for the manuscript below. It holds the model code, the datasets, the trained weights, the result files, the figures and tables, and the deployed applications.

Phutthananon, C., Youwai, S., Kongkitkul, W. A deflection-basin fusion transformer for critical pavement strains without backcalculation. Manuscript under review.

The Deflection-Basin Fusion Transformer (DBFT) predicts two critical pavement strains in one step. It reads the falling weight deflectometer (FWD) basin and the layer thicknesses. It never forms layer moduli, so backcalculation leaves the inference chain. The model has 0.22 M parameters.

  • Fatigue criterion: horizontal tensile strain at the bottom of the asphalt layer, εac.
  • Rutting criterion: vertical compressive strain at the top of the subgrade, εsg.

Both strains return in 1.6 ms on one CPU thread. In batch the cost is 0.15 ms per drop.

Run the model without installing anything at huggingface.co/spaces/Sompote/FWD.

python app/cli.py predict -d 171 154.5 145.1 89.6 62.8 47.4 32.9 22.6 17.9 -t 100 150 300
# AC tensile strain (bottom of asphalt):       25.4 ue
# Subgrade compressive strain (top of SG):    135.0 ue

What the model replaces

FWD deflection basin, the two critical strains, and the conventional two-step route versus DBFT

Mechanistic-empirical evaluation of a flexible pavement rests on εac and εsg. Routine practice measures neither. Both follow from the basin in two steps. First, backcalculate the layer moduli. Second, propagate those moduli through a forward layered-elastic analysis. The inverse step is ill-posed and non-unique. It is sensitive to thickness and deflection error, and the second step compounds that error. It also runs in the office, on a returned data file, not during the survey.

DBFT predicts both strains in a single forward pass. Its inputs are what the survey already returns: the nine-geophone basin D0 to D1800 and the three layer thicknesses. Nothing downstream changes. Transfer functions, allowable repetitions, remaining life and overlay design all stay as they are.


Model

DBFT architecture

The model reads the basin as a sequence indexed by physical geophone offset. Four elements define the architecture. All of them live in code/fwd_fusion_transformer.py.

  1. Continuous sensor-offset positional encoding. Fourier features of the offset in mm. The encoder therefore sees the true non-uniform geometry of 0, 200, 300, 450, 600, 900, 1200, 1500 and 1800 mm, not a token index.
  2. Physics-index tokens. SCI, BDI, BCI, AREA and AUPP enter as five extra tokens beside the nine deflection tokens.
  3. Thickness branch with FiLM. The thickness code modulates every basin token. It also joins the encoder memory as its own token.
  4. Strain-query decoder. One learnable query per target cross-attends over the fused memory. Each query yields its own attention map.

The encoder has 3 layers and the decoder 2, with d_model 64 and 4 heads. The parameter count is 224,961.


Results

Exact theory

The test set is 15 % of the 2,430-case EVERSTRESS factorial. DBFT halves the error of the strongest conventional baseline. RMSE is in με.

Model R² εac RMSE εac R² εsg RMSE εsg
DBFT 0.99977 0.99 0.99986 1.24
MLP 0.99913 1.92 0.99944 2.45
Gradient boosting 0.99883 2.23 0.99917 2.99
Random forest 0.99545 4.39 0.99372 8.22

At these errors the model is a lossless substitute for the two-step forward computation. The ablations in results/results.json show the thickness branch is required. Removing it raises RMSE by a factor of three to five.

Real roads

Three survey routes were withheld in full, giving 1,374 test points. A model trained on the factorial alone fails on measured basins. The field domain reverses the sign of the relationship between the outer basin and subgrade strain. The combined surrogate-and-field objective repairs that failure.

Field accuracy on the held-out routes

Configuration R² εac RMSE εac R² εsg RMSE εsg
DBFT combined, λf = 1.0, extended surrogate (deployed) 0.964 28.7 0.879 64.7
MLP, same pooled data and holdout* 0.945 35.4 0.847 72.6
Random forest, same pooled data and holdout 0.938 37.7 0.803 82.4
Gradient boosting, same pooled data and holdout 0.915 44.0 0.807 81.8
DBFT trained on the factorial surrogate only −0.045 154.4 0.141 172.4

* The stronger of the two MLP weightings in results/results_baselines_combined.json. With the field label-quality weight applied it reaches 0.944 and 0.825.

The deployed model holds R² ≥ 0.993 on the extended-surrogate test split. Field accuracy therefore costs nothing in theoretical accuracy. The objective does most of the repair. The architecture removes a further 19 % of the field RMSE on εac and 11 % on εsg.

Attribution

SHAP attribution

SHAP over the 12 measurable inputs recovers recognised mechanics. The fatigue criterion is curvature-driven and rests on D0 and D300. The subgrade criterion draws on the whole basin. It includes the D1200 to D1800 range, which no routine basin index reaches.

The field labels come from ELMOD backcalculation. Field agreement is therefore with backcalculation-consistent mechanics, not with gauge-measured strain. On the quarter of held-out basins that ELMOD fitted best, the fatigue error falls to 15.4 με. code/label_quality_analysis.py reproduces that stratification.


Install

Python 3.11. CPU is enough.

git clone https://github.com/Sompote/DBFT.git
cd DBFT
pip install -r requirements.txt

Quick start

Use the deployed model, trained with the combined objective on the extended surrogate.

# one FWD point: 9 deflections in um at 707 kPa, then 3 thicknesses in mm
python app/cli.py predict -d 171 154.5 145.1 89.6 62.8 47.4 32.9 22.6 17.9 -t 100 150 300

# add the local SHAP attribution
python app/cli.py predict -d ... -t 100 150 300 --explain

# a whole survey file
python app/cli.py batch survey.xlsx -o strains.xlsx

# REST API on port 8000, with the React UI if the front end is built
python app/cli.py serve

The Section 4 model of the paper is separate. It was trained on the factorial surrogate alone. code/predict.py serves it.

python code/predict.py --d0 663 --d200 594 --d300 547 --d450 483 --d600 430 \
                       --d900 344 --d1200 281 --d1500 234 --d1800 197 \
                       --asphalt 150 --base 250 --subbase 350

Put basins on the standard load first: 707 kPa on a plate of 150 mm radius. A basin measured at another load scales linearly.


Repository layout

The root holds only folders and the three repository files. Every script resolves its inputs and outputs through code/paths.py, so it runs from any working directory.

code/     the model, training, analysis and figure scripts, and the solver
data/     the four datasets
weights/  trained models, their scalers and their held-out predictions
results/  the metric files behind every table
figures/  generated figures (empty until a figure script runs)
paper/    manuscript figures, tables, captions and Appendix A
docs/     the images used in this README
app/      the deployed CLI, API, web UI and Gradio app
Path What it is
code/paths.py The folder constants. Change a location here, not in fifteen scripts.
code/fwd_fusion_transformer.py The model, Standardizer, basin_indices(), load_dataset() and the column constants. Every other script imports from it.
code/train_dbft.py Surrogate-only training, the RF, GB and MLP baselines and the ablations of Section 4. Writes weights/dbft_model.pt and results/results.json.
code/train_dbft_combined.py Joint surrogate and field training, Section 5. Writes weights/dbft_<tag>.pt, results/results_<tag>.json, the scalers and the held-out predictions.
code/train_baselines_combined.py RF, GB and MLP on the same pooled data and route holdout. Writes results/results_baselines_combined.json.
code/predict.py Inference CLI for weights/dbft_model.pt, single point or batch Excel.
code/shap_analysis.py SHAP attribution of the 12 measurable inputs for the deployed model.
code/label_quality_analysis.py Held-out accuracy stratified by the ELMOD basin-fit RMS.
code/extract_field_data.py Parses the raw Dynatest and ELMOD reports into data/field_data.csv.
code/compute_le_labels.py Recomputes the field strain labels with PyMastic at the standard load, giving data/field_dataset.csv.
code/generate_extended_surrogate.py Builds data/strain_result_extended.csv, the factorial plus 11,744 PyMastic solutions over the field domain.
code/make_*.py The paper figures. They write into figures/.
code/pymastic/ The vendored PyMastic layered-elastic solver, with one overflow patch. See code/pymastic/README.md.
paper/ The manuscript figures, all eleven tables as CSV, the full captions and the Appendix A pseudocode. See paper/README.md.
app/ The deployment code: FastAPI backend, React front end, Gradio app, CLI and Dockerfile. It mirrors Sompote/FWD2Strain.

Data

File Rows What it is
data/strain_result.xlsx 2,430 The original EVERSTRESS factorial.
data/strain_result_extended.csv / .xlsx 14,174 The factorial plus PyMastic solutions resampled over the field structure space. Prefer the CSV. pd.read_excel on the 14k-row workbook takes about 30 s.
data/field_data.csv 21,260 The direct extract of the DOH reports, before filtering. Every drop, variant and load level, with the measured plate pressure, the temperatures, the backcalculated moduli E1 to E5, the ELMOD strains at every interface and the basin-fit RMS.
data/field_dataset.csv 7,721, of which 7,651 survive filtering The training form. 96 sections on 20 numbered highways, basins rescaled to 707 kPa, strain labels recomputed with PyMastic from the ELMOD moduli.

The raw Dynatest and ELMOD survey reports (.F25, .ems, .sN) are the property of the Thai Department of Highways. They are not redistributed here. code/extract_field_data.py is included so the extraction stays auditable, but it needs those files. Its output is committed, so the pipeline can be followed from the first tabular form onwards: data/field_data.csv, then code/compute_le_labels.py, then data/field_dataset.csv, then training.

Trained weights

File Trained on Field R², εac / εsg
weights/dbft_combined_lam1.0_ext.pt Extended surrogate and field, λf = 1.0 0.964 / 0.879. Deployed in both apps.
weights/dbft_combined_lam0.5_ext.pt, weights/dbft_combined_lam0.25_ext.pt The same, at other loss weights Loss-weight sensitivity.
weights/dbft_surrogate_only_ext.pt Extended surrogate only 0.78 / 0.50, with no measured data in the loss.
weights/dbft_field_only.pt Field only Field-only ablation.
weights/dbft_combined_lam*.pt, no _ext Original factorial and field Section 5 ablation.
weights/dbft_model.pt Factorial surrogate only The Section 4 model, used by predict.py.

Each _ext model stores its input scalers in weights/*_scalers.npz. weights/dbft_model.pt does not. predict.py refits them from the training split under seed 42.


Reproducing the paper

Training the deployed model takes about 1 to 2 h for 600 epochs.

python code/train_dbft_combined.py --mode combined --lambda-field 1.0 \
       --surrogate-data data/strain_result_extended.csv --device cpu

Always pass --device cpu. On Apple mps this training silently fails on the extended dataset. The loss stays flat near 0.3 and then diverges to NaN. Identical settings converge on CPU, which is also about 3× faster for a model this small.

The other configurations:

python code/train_dbft.py                                       # Section 4: surrogate, baselines, ablations
python code/train_dbft_combined.py --mode surrogate_only --surrogate-data data/strain_result_extended.csv --device cpu
python code/train_dbft_combined.py --mode field_only --device cpu
python code/train_baselines_combined.py                         # RF, GB and MLP under the same holdout
python code/shap_analysis.py                                    # Figure 16 and results/shap_values_ext.npz
python code/label_quality_analysis.py                           # Table 11

The tag takes an _ext suffix whenever --surrogate-data is not the default. That keeps the factorial-trained artifacts intact.

Regenerating the extended surrogate is one command. The script first checks itself against the factorial and aborts if PyMastic does not reproduce it.

python code/generate_extended_surrogate.py

The manuscript figures and every table as CSV are in paper/. Its README maps each figure and each table to the script or result file behind it. The figure scripts live in code/ and write into figures/, except the two survey figures, which write into paper/figure/. They are make_figures.py, make_extended_figures.py, make_ext_results_figure.py, make_surrogate_comparison_figure.py, make_surrogate_vs_elmod_figure.py, make_fwd_schematic_figure.py, make_field_map_figure.py and make_field_survey_figures.py.

Conventions that must hold

  • The load is 707 kPa on a plate of 150 mm radius. Poisson's ratio is 0.35 for asphalt and 0.40 for every other layer.
  • Geophone offsets are 0, 200, 300, 450, 600, 900, 1200, 1500 and 1800 mm. Units are kPa, mm, μm and με.
  • Splits are seeded with np.random.default_rng(42). The surrogate split is 70/15/15.
  • Field evaluation holds out entire routes, listed as TEST_ROUTES in code/train_dbft_combined.py. A random point split leaks through spatial autocorrelation and overstates accuracy.
  • A field structure may have no subbase, h₃ = 0. The third layer then collapses and E₃ becomes the subgrade. Any new solver code must do the same.

Apps

Web interface

One set of weights is reachable four ways. All of the code sits in app/, which mirrors Sompote/FWD2Strain.

  • CLI. python app/cli.py predict | batch | serve | info.
  • REST API. FastAPI. Run python app/cli.py serve, or cd app && STATIC_DIR=frontend/dist uvicorn backend.main:app --port 8000.
  • Web UI. React and Vite in app/frontend. Build it once with cd app/frontend && npm install && npm run build.
  • Gradio. cd app/app_gradio && python app.py. This is the app that runs the Hugging Face Space.

Prediction logic lives in app/backend/core.py and every front end shares it. A physically invalid point is refused with a reason, not evaluated quietly. After retraining, copy the weights and scalers into app/backend/assets/ and app/app_gradio/assets/. app/backend/prepare_assets.py does that.


Citation

@article{phutthananon_dbft,
  title   = {A deflection-basin fusion transformer for critical pavement strains without backcalculation},
  author  = {Phutthananon, Chana and Youwai, Sompote and Kongkitkul, Warat},
  note    = {Manuscript under review},
  year    = {2026}
}

Artificial Intelligence Research Group, Department of Civil Engineering, King Mongkut's University of Technology Thonburi (KMUTT), Bangkok, Thailand.

Licence

MIT, in LICENSE. The vendored solver in pymastic/ is PyMastic by Mostafa Nakhaei, under Apache-2.0, with one numerical patch. pymastic/README.md documents it. Neither licence covers the Thai DOH survey reports, which are not included.

About

Deflection-Basin Fusion Transformer: the two critical pavement strains predicted in one step from an FWD deflection basin and layer thicknesses, with no backcalculation. Training pipeline, datasets, trained weights, CLI, API and web apps.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages