File size: 7,928 Bytes
3046edb 256b4e9 3046edb 256b4e9 52366e1 256b4e9 14db1c8 256b4e9 52366e1 256b4e9 14db1c8 256b4e9 14db1c8 256b4e9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | ---
license: mit
library_name: pytorch
pipeline_tag: tabular-regression
tags:
- set-transformer
- chemberta
- radiation-shielding
- x-ray
- materials-science
- monte-carlo-surrogate
---
# STAR-XPC
STAR-XPC predicts how much of an X-ray beam passes through a polymer composite
shield. You give it a polyethylene slab loaded with fillers, a slab thickness
and a tube voltage. It returns the transmission ratio **I/I₀** in milliseconds.
The penEasy (PENELOPE) Monte Carlo simulations it was trained to replace take
hours per point. The training data were generated with
[attenupy](https://github.com/cmpe-netlab41/attenupy), which designs, runs and
collects these penEasy shielding studies.
The composite is treated as a *set* of ingredients. Each ingredient is described
by a ChemBERTa embedding of its SMILES and its weight fraction, and a Set
Transformer maps the set plus four physics features to I/I₀. Because the
chemistry enters through SMILES, you can also register materials the model was
not trained on.
## Quickstart
```bash
pip install torch numpy safetensors huggingface_hub
```
```python
import sys
from huggingface_hub import snapshot_download
repo = snapshot_download("cmpe-netlab41/STAR-XPC")
sys.path.insert(0, repo)
from star_xpc import STARXPC
model = STARXPC.from_pretrained(repo)
# 40 wt% Bi + 30 wt% W in polyethylene (the remaining 30 wt%), 80 kVp beam
y = model.predict({"Bi": 0.40, "W": 0.30}, thickness_mm=[0.25, 0.5, 1.0, 1.5], kvp=80)
print(y) # I/I0 at each thickness
```
`predict` works out the composite's density and mean excitation energy from the
composition, so the composition, thickness and voltage are all you need.
## Inputs
| Argument | Meaning | Unit |
|---|---|---|
| `fillers` | Filler weight fractions of the **whole** composite, e.g. `{"Bi2O3": 0.4, "BaSO4": 0.4}`. Up to 10 fillers | fraction (0.4 = 40 wt%) |
| `thickness_mm` | Slab thickness, scalar or array | mm |
| `kvp` | X-ray tube voltage, scalar or array (broadcast with thickness) | kVp |
| `polymer_fraction` | Polyethylene weight fraction. Defaults to `1 - sum(fillers)` | fraction |
| `mass_den` | Composite density. Computed if omitted | g/cm³ |
| `mean_excit` | Composite mean excitation energy. Computed if omitted | eV |
## Materials
The model ships with the materials it was trained on:
- **Fillers:** B, B4C, BN, Ba, BaSO4, Bi, Bi2O3, Cu, Sb, Sn, W, WO3
- **Matrix:** polyethylene (C2H4)
### Registering a new material
Any other filler can be registered from its SMILES. It is embedded with ChemBERTa
(`seyonec/ChemBERTa-zinc-base-v1`, pinned revision) using exactly the recipe the
training materials went through. For example, lead and gadolinium, which are not
in the training data:
```python
# pip install transformers
model.add_material("Pb", smiles="[Pb]", density=11.34)
model.add_material("Gd", smiles="[Gd]", density=7.90)
model.predict({"Pb": 0.70}, thickness_mm=[0.3, 0.6, 1.2], kvp=100)
model.predict({"Gd": 0.40, "W": 0.30}, thickness_mm=1.0, kvp=120)
```
Registered this way, Pb and Gd reach NMSE % 0.19 and 0.20 against penEasy at
100 kVp. That is somewhat above the held-out sets of trained materials, which
range from 0.01 to 0.13 (see [results](#held-out-test-results)).
- **Formula:** read from the name when the name is a chemical formula (`"Pb"`,
`"Gd2O3"`). Otherwise pass `formula="..."`.
- **Density:** in g/cm³, used to compute the composite density. Without a
formula or density, pass `mass_den=` and `mean_excit=` to `predict` instead.
- **Style:** write SMILES the way the training materials were written. Use pure
elements as bracket atoms (`[Pb]`), oxides as covalent structures
(`O=[Gd]O[Gd]=O`, `O=[W](=O)=O`), and salts as ions
(`[Ba++].[O-]S(=O)(=O)[O-]`). Keep SMILES under 64 tokens, since longer ones
are truncated and you get a warning.
- **Unregistered names:** using one raises an error that shows the
`add_material` call to make.
- **Accuracy:** `predict` warns once for each material that is not in the
training data. Treat those predictions as estimates and confirm important
ones with Monte Carlo. [attenupy](https://github.com/cmpe-netlab41/attenupy)
sets up and runs those simulations.
## Physics features
- **Mean excitation energy:** the Bragg additivity rule with PENELOPE's elemental
I-values for Z = 1–99, so it also works for registered materials. This is what
PENELOPE's `material` program does, and it matches the training data to within
10⁻⁴.
- **Density:** the inverse rule of mixtures. It uses the training densities for
the bundled materials and the density you pass for registered ones.
- **If you know better:** some boron-containing training samples used a slightly
different boron density. If you have the exact values from PENELOPE, pass
`mass_den=` and `mean_excit=`.
## Batch prediction from a table
`predict_frame` takes a pandas DataFrame in the training-data schema:
`molecule_1..10`, `ratio_1..10` (filler wt%), `polymer`, `polymer_ratio`
(fraction), `geo_number_mm` (**in units of 0.01 mm**, so 100 = 1 mm), `spc`
(kVp), `mass_den` and `mean_excit`.
```python
import pandas as pd
y = model.predict_frame(pd.read_csv("my_samples.csv"))
```
## Training domain and limitations
- **Target:** the energy deposited in an air detector behind the slab, divided
by the same quantity with the slab replaced by air. It comes from penEasy
simulations of a fixed slab-and-detector geometry.
- **Beams:** four spectra. 30 kVp is ISO N-30, 80 kVp is IEC RQR6, 100 kVp is
IEC RQR8 and 120 kVp is IEC RQR9. Other voltages are interpolation between
those spectra and are untested.
- **Thickness:** 0.15–2.5 mm.
- **Composition:** polyethylene at 20–40 wt%, with one to several fillers making
up the remaining 60–80 wt%.
- **Output range:** the output layer is unbounded, so predictions near 0 or 1
can land slightly outside that range.
- **Warnings:** `predict` warns when an input falls outside the training domain.
## Held-out test results
None of these test sets were used in training. Each has 10 thicknesses.
| Test set | NMSE % | RMSE | MAPE (10 % trimmed) |
|---|---:|---:|---:|
| Bi–W, 80 kVp | 0.129 | 0.0109 | 6.86 % |
| W–Cu–B, 100 kVp | 0.00724 | 0.0042 | 0.65 % |
| Bi–Sb, 120 kVp | 0.0469 | 0.0106 | 2.65 % |
| Bi₂O₃–BaSO₄, 80 kVp | 0.0865 | 0.0095 | 4.89 % |
| BaSO₄–WO₃, 100 kVp | 0.0167 | 0.0064 | 1.78 % |
| Bi₂O₃, 120 kVp | 0.0113 | 0.0053 | 1.22 % |
| **Pb** 70 wt% (registered), 100 kVp | 0.192 | 0.0167 | 5.24 % |
| **Gd** 70 wt% (registered), 100 kVp | 0.198 | 0.0195 | 4.03 % |
NMSE % = 100 · MSE / mean(y²).
## How it works
Each composite becomes a set of 11 slots (up to 10 fillers plus the polymer,
zero-padded). Each slot is a 773-d vector:
- the ingredient's 768-d ChemBERTa embedding, which is the mean of the last 4
hidden layers, masked-mean-pooled over tokens and L2-normalised;
- its share of the composition;
- four z-scored global features: tube voltage, composite density, thickness and
mean excitation energy. The z-score statistics are those of the model's
training split and are stored in `config.json`.
A Set Transformer (2 ISAB blocks with 64 inducing points, PMA with 8 seeds and a
SAB; width 256, 32 heads) turns the set into a single output.
In the training data, filler amounts were stored in wt% and the polymer amount
as a fraction, and the two were renormalised together. `star_xpc.py`
reproduces that encoding, so give `predict` ordinary weight fractions.
## Files
| File | Contents |
|---|---|
| `star_xpc.py` | Model definition and the `STARXPC` predictor |
| `model.safetensors` | Set Transformer weights |
| `embeddings.safetensors` | ChemBERTa embeddings of the 13 training materials |
| `config.json` | Architecture, feature normalisation statistics, material table, training domain |
## Citation
<!-- TODO: add the paper's BibTeX once it is available -->
|