Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5b53f02
move creation of form object outside cgi_call
bmaranville Jun 16, 2022
5bfa08a
adding pyodide version of calculator
bmaranville Jun 16, 2022
a716abb
remove debugging statement
bmaranville Jun 16, 2022
058c936
make worker_ready message more distinct
bmaranville Jun 16, 2022
1d5488f
fix call to cgi_call
bmaranville Jun 16, 2022
2bfb988
adding service worker version of page
bmaranville Oct 25, 2022
57e4173
adding message back to client(s) when service worker is ready
bmaranville Oct 25, 2022
bd45628
improve loading lifecycle for python code
bmaranville Oct 25, 2022
62251d0
adding check for hard refresh - does a second soft reload to re-activ…
bmaranville Oct 25, 2022
0ba99c9
use separate fetch command to make sure pyodide is ready
bmaranville Oct 25, 2022
e81baa3
udpate pyodide version
bmaranville Jun 7, 2024
fd68a34
Merge branch 'python-periodictable:master' into master
bmaranville Dec 9, 2024
856f0d7
updates from upstream index.html
bmaranville Dec 9, 2024
aa97983
revert payload extraction from event
bmaranville Dec 9, 2024
1d78352
wait for the worker to be ready
bmaranville Dec 9, 2024
50ee09e
Merge remote-tracking branch 'upstream/master'
bmaranville Feb 11, 2026
69f40fa
Merge remote-tracking branch 'origin/master' into pyodide
bmaranville Feb 11, 2026
3439f40
make cgi a lazy import
bmaranville Feb 12, 2026
0a00757
update pyodide version
bmaranville Feb 12, 2026
faea11d
update pyodide version
bmaranville Feb 12, 2026
8e49aa8
adding new version that allows immediate interaction with the page
bmaranville Feb 12, 2026
0c0d834
use module webworker
bmaranville Feb 25, 2026
d56564d
add workflow for deploying to gh-pages
bmaranville Feb 25, 2026
c5dca96
add script for getting static pyodide libraries we need
bmaranville Feb 25, 2026
1c99490
use new script for getting pyodide
bmaranville Feb 25, 2026
e469fe9
use local pyodide
bmaranville Feb 25, 2026
1ed74f5
use local nact.py
bmaranville Feb 25, 2026
c706e2c
add favicon.ico to site
bmaranville Feb 25, 2026
bdeb709
adding deploy script
bmaranville Feb 25, 2026
bd3fb8d
add helper file that contains full path to periodictable local wheel
bmaranville Feb 25, 2026
ab53c1a
use new deployment all-in-one script
bmaranville Feb 25, 2026
325e3ce
use new manifest file to get full path to periodictable local wheel
bmaranville Feb 25, 2026
98b9cc5
use unicode arrows in table headers instead of GIF from vendored theme
bmaranville Feb 25, 2026
a5cfdf4
need to export env variables for them to be picked up by deploy.sh
bmaranville Feb 25, 2026
050e9ed
fix table sorting
bmaranville Feb 25, 2026
7443d2d
use pip3 since legacy installs will use that
bmaranville Feb 25, 2026
0f3c833
rename deploy script because there will be more than one
bmaranville Feb 25, 2026
c8ca32d
use renamed deploy script
bmaranville Feb 25, 2026
f3d0e48
remove unused page
bmaranville Feb 25, 2026
395017f
remove another unused page
bmaranville Feb 25, 2026
32e3e1d
adding shared css
bmaranville Feb 25, 2026
28bd6e2
use shared css
bmaranville Feb 25, 2026
f07c4d1
capture errors and return to client, like is done in cgi interface
bmaranville Feb 27, 2026
3ea73f1
move api connection to separate script, and move shared main app code…
bmaranville Feb 27, 2026
1d8054d
adding main app code
bmaranville Feb 27, 2026
8457a4c
index.html is the same as the pyodide version, except for API definition
bmaranville Feb 27, 2026
6f7bbaa
add API for fetch interface (CGI)
bmaranville Feb 27, 2026
49cbead
initialize API after page is done rendering
bmaranville Feb 27, 2026
b854322
renamed api script
bmaranville Feb 27, 2026
ffb7a4a
adding API for webworker (pyodide)
bmaranville Feb 27, 2026
f7b990f
use dict intput to api_call, convert cgi to dict
bmaranville Feb 27, 2026
63ed18c
just pass JSON
bmaranville Feb 27, 2026
fd605fb
default index.html is webworker version (replaced in local servers)
bmaranville Feb 27, 2026
a1fe2e1
nact.py api_call takes a plain dict (JSON) now, no need to fake CGI f…
bmaranville Feb 27, 2026
2714602
json dict always includes mass, even if empty, so handle that, and ex…
bmaranville Feb 27, 2026
79d8bda
add regex replace to load the api_cgi.js API in the page, replacing a…
bmaranville Feb 27, 2026
d46b321
update readme for json API and flask server
bmaranville Feb 27, 2026
4f6cd2e
remove server.py, replace with flask_server.py and cgi_server.py
bmaranville Feb 27, 2026
f59b588
use index_template, and render it with periodictable version and webw…
bmaranville Feb 27, 2026
23d76c3
removing deprecated files
bmaranville Feb 27, 2026
dc050d9
adding flask server
bmaranville Feb 27, 2026
422e5b6
update sample query
bmaranville Feb 27, 2026
785bed8
replacing duplicate html with single index_template.html
bmaranville Feb 27, 2026
d1aa1d9
need css and all js scripts in deployment
bmaranville Feb 27, 2026
a25de2a
add pyodide build artifacts to .gitignore
bmaranville Feb 27, 2026
76aa759
use macos-friendly sed invocation
bmaranville Feb 27, 2026
4b718b1
add pyodide deploy and test instructions
bmaranville Feb 27, 2026
ea81f87
BSD (macos) and GNU-friendly invocation of tar
bmaranville Feb 27, 2026
ed65f78
need to nudge GNU tar with env variable that BSD ignores
bmaranville Feb 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Deploy static site to GitHub Pages

on:
push:
branches:
- pyodide # Triggers the workflow on pushes to the pyodide branch
workflow_dispatch: # Allows manual triggering from the GitHub UI

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout your repository
uses: actions/checkout@v4
# Add steps to build your static site (e.g., npm run build)
- name: Run deployment script
run: |
export PYODIDE_VERSION=0.29.3
export TARGET_DIR=dist
./deploy_calculator.sh
- name: Upload artifact
# The contents of the 'build' directory will be uploaded as an artifact
uses: actions/upload-pages-artifact@v4
with:
path: 'dist/' # Change this to your build output directory (e.g., public, dist)

deploy:
# Add a dependency to the build job
needs: build
runs-on: ubuntu-latest
permissions:
pages: write # Grants the GITHUB_TOKEN the necessary permissions to deploy to GitHub Pages
id-token: write # Required for OIDC authentication
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4 # This action handles the deployment
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ endf/MT.DAT
endf/PLOT.CHR
endf/PLOT.SYM
endf/*.out

# pyodide build cruft
activation/pyodide
activation/periodictable_wheel_name.txt
217 changes: 125 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,8 @@ available on [github](https://github.com/pkienzle/periodictable).
Installation
============

The activation web frontend is in the activation subdirectory and the cgi
backend is in cgi-bin. Update the server with something like:

sudo cp -rp activation/* /var/www/resources/activation
sudo cp -p cgi-bin/nact.py /var/www/cgi-bin

The web page uses the date of activate/index.html to show the last
modification date on the program, so be sure to preserve attributes in copy.
The activation web frontend is in the activation subdirectory.
The backend API is in the cgi-bin folder (nact.py)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need pyodide instructions. Something like:

You can make a serverless install using pyodide to run the backend API. The `deploy_calculator.sh`
script will install to `/var/html/resources/activation/index.html`.

To test the pyodide version before deploying, install into a temporary directory:
```sh
TARGET_DIR=/tmp/pt bash deploy_calculator.sh
(cd /tmp/pt && python -m http.server)
```
You can then navigate to http://localhost:8000/index.html to view the application.


Be sure the web server is configured to use python 3, with the periodictable
package updated to the latest version:
Expand All @@ -33,15 +27,16 @@ of updates this will also set the last modification date on index.html.

For testing you can run the server from the repository:

python server.py [host | host:port]
pip install flask
python flask_server.py [host | host:port]

Additional files:

* endf/* was used to generate the graphs of thermal resonances. It is not
needed unless you wish to update the graphs, for example, when new versions of
the endf database are released.

* server.py is used to run a test server for debugging the web application, or
* flask_server.py is used to run a test server for debugging the web application, or
showing potential new features to users. See the help inside the file for
details on running the server.

Expand All @@ -50,6 +45,19 @@ Additional files:

* cgi-bin/hello.py is a minimal test script for python cgi.

Pyodide implementation
======================
You can make a serverless install using pyodide to run the backend API. The `deploy_calculator.sh`
script will install to `/var/html/resources/activation/index.html`.

To test the pyodide version before deploying, install into a temporary directory:
```sh
TARGET_DIR=/tmp/pt bash deploy_calculator.sh
(cd /tmp/pt && python -m http.server)
```
You can then navigate to http://localhost:8000/index.html to view the application.


Backend interface
=================

Expand Down Expand Up @@ -84,6 +92,25 @@ request = {
}
```

```python
python_request = {
'calculate': "all", # target is "scattering" or "activation" or "all"
'sample': 'Co', # Material
'flux': '100000', # Thermal flux
'Cd': '0', # Cd ratio
'fast': '0', # Thermal/fast ratio
'mass': '0', # Mass
'exposure': '1', # Time on beam
'rest': ["0","1","24","360"], # Time off beam
'density': '0', # Density
'thickness': '1', # Thickness
'wavelength': '1', # Source neutrons
'xray': 'Cu Ka', # Source Xrays
'decay': '0.001', # target for "Time to decay below"
'abundance': 'IAEA' # natural abundance tables (IAEA or NIST)
}
```

The response is a JSON object with the following fields
```javascript
response = {
Expand Down Expand Up @@ -148,119 +175,125 @@ Example
-------

```sh
$ curl -s -d "sample=Co" -X POST https://www.ncnr.nist.gov/cgi-bin/nact.py | python -m json.tool
$ curl -s -d '{"sample": "Co"}' -H "Content-Type: application/json" -X POST http://localhost:8008/api/calculate | python -m json.tool
{
"sample": {
"name": "Co",
"density": 8.9,
"natural_density": 8.9,
"thickness": 1.0,
"mass": 1.0,
"formula": "Co"
},
"activation": {
"flux": 100000.0,
"decay_level": 0.001,
"total": [
0.5088248094656863,
0.009706843055148993,
1.550197781340068e-05,
1.5423998799711213e-05
],
"rest": [
0,
1,
24,
360
],
"Cd": 0.0,
"activity": [
{
"reaction": "act",
"product": "Co-60",
"halflife": "5.272 y",
"comments": "s for 10m isomer added to ground state",
"comments": "",
"halflife": "10.5 m",
"isotope": "Co-59",
"levels": [
1.550756280503848e-05,
1.5507330056885684e-05,
1.5501977813400642e-05,
1.5423998799711213e-05
0.5087467869376632,
0.009690144997026036,
2.6447704770864502e-42,
0.0
],
"isotope": "Co-59"
"product": "Co-60m+",
"reaction": "act"
},
{
"reaction": "act",
"product": "Co-60m+",
"halflife": "10.5 m",
"comments": "",
"comments": "Co-61 prod from Co-60m only",
"halflife": "1.65 h",
"isotope": "Co-59",
"levels": [
0.5088093019028804,
0.009691335725091536,
2.6450954673146495e-42,
0.0
7.305869373119584e-16,
4.799870068457319e-16,
3.0552994658480865e-20,
1.52897407497221e-81
],
"isotope": "Co-59"
"product": "Co-61",
"reaction": "2n"
},
{
"reaction": "2n",
"product": "Co-61",
"halflife": "1.65 h",
"comments": "Co-61 prod from Co-60m only",
"comments": "s for 10m isomer added to ground state",
"halflife": "5.272 y",
"isotope": "Co-59",
"levels": [
7.306767120646388e-16,
4.800459878001244e-16,
3.055674902007567e-20,
1.5291619557875176e-81
1.5505657464889658e-05,
1.5505424745333514e-05,
1.5500073159453058e-05,
1.5422103726672467e-05
],
"isotope": "Co-59"
"product": "Co-60",
"reaction": "act"
},
{
"reaction": "2n",
"product": "Co-61",
"halflife": "1.65 h",
"comments": "Co-61 prod assuming all Co-60m has decayed to Co-60",
"halflife": "1.65 h",
"isotope": "Co-59",
"levels": [
1.3649499897275873e-16,
8.967560554449202e-17,
5.7081926346341585e-21,
2.8565705754412276e-82
1.3647822848511002e-16,
8.966458753177e-17,
5.707491296308241e-21,
2.8562196022780084e-82
],
"isotope": "Co-59"
"product": "Co-61",
"reaction": "2n"
}
],
"decay_level": 0.001,
"decay_time": 1.5773360047132599,
"exposure": 1.0,
"decay_time": 1.5773675158317233,
"fast": 0.0,
"Cd": 0.0
"flux": 100000.0,
"rest": [
0,
1,
24,
360
],
"total": [
0.508762292595129,
0.00970565042177194,
1.5500073159453095e-05,
1.5422103726672467e-05
]
},
"sample": {
"density": 8.9,
"formula": "Co",
"formula_latex": "Co",
"mass": 1.0,
"name": "Co",
"natural_density": 8.9,
"thickness": 1.0
},
"scattering": {
"sld": {
"real": 2.2645416201426363,
"imag": 0.009403091502484154,
"incoh": 5.632988294016107
"contrast_match": {
"D2O_fraction": 0.4066002243307043,
"sld": 2.2645414633790257
},
"xs": {
"coh": 0.07085810248318081,
"abs": 1.8806183004968307,
"incoh": 0.43843639843243204
},
"penetration": 0.4184253079898973,
"neutron": {
"wavelength": 1.0,
"energy": 81.80420235572412,
"velocity": 3956.0339760560055
"energy": 81.80421023488275,
"velocity": 3956.0340061039888,
"wavelength": 1.0
},
"transmission": 9.163767420488476
"penetration": 0.4184253369555237,
"sld": {
"imag": 0.009403090851552168,
"incoh": 5.632980055822083,
"real": 2.2645414633790257
},
"transmission": 9.16376893656492,
"xs": {
"abs": 1.8806181703104334,
"coh": 0.07085931929382916,
"incoh": 0.4384351463657107
}
},
"success": true,
"version": "2.0.2",
"xray_scattering": {
"xray": {
"wavelength": 1.5418,
"energy": 8.041522080237366
},
"sld": {
"real": 63.020248367719645,
"imag": 9.14097379704212
"imag": 9.140742563282087,
"real": 63.02025244915057
},
"xray": {
"energy": 8.041522793695698,
"wavelength": 1.5418
}
},
"success": true
}
}
```
25 changes: 25 additions & 0 deletions activation/api_fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class FetchAPI {
response_callback = null;
url = null;

initialize (response_callback, ready_callback=() => {}, url="/api/calculate") {
this.response_callback = response_callback;
this.url = url;
ready_callback();
}

submit(data) {
fetch(this.url, {
method: "POST",
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(json => this.response_callback(json))
.catch(error => this.response_callback({'success':false,'detail':{'fetch error':error}}));
}
}

const API = new FetchAPI();
29 changes: 29 additions & 0 deletions activation/api_webworker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class WebWorkerAPI {
response_callback = null;
ready_callback = null;
url = null;
pyodideWorker = null;

initialize (response_callback, ready_callback=() => {}, url="./webworker.js") {
this.response_callback = response_callback;
this.ready_callback = ready_callback;
this.url = url;
this.pyodideWorker = new Worker(this.url, {type: "module"});
this.pyodideWorker.onmessage = (event) => {
if ('worker_ready' in event.data) {
this.ready_callback();
}
else {
this.response_callback(event.data);
}
}
}

submit(data) {
this.pyodideWorker.postMessage({
data: data
});
}
}

const API = new WebWorkerAPI();
Loading