diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..c4dd004 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -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 diff --git a/activation/css/footer.css b/activation/css/footer.css new file mode 100644 index 0000000..807fb95 --- /dev/null +++ b/activation/css/footer.css @@ -0,0 +1,10 @@ +.footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.5rem; +} + +.footer .contacts { + flex: 1; +} diff --git a/activation/css/loading-spinner.css b/activation/css/loading-spinner.css new file mode 100644 index 0000000..235b010 --- /dev/null +++ b/activation/css/loading-spinner.css @@ -0,0 +1,30 @@ +.loader .spinner { + border: 4px solid #f3f3f3; /* Light grey background */ + border-top: 4px solid #3498db; /* Blue "spinning" part */ + border-radius: 50%; + width: 30px; + height: 30px; + animation: spin 1s linear infinite; +} + +.loader.finished { + display: none; +} + +.loader { + display: flex; + align-items: center; + gap: 10px; + margin: 0 auto; + width: fit-content; + padding: 1em; +} + +.loader.not-started { + display: none; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} diff --git a/activation/css/main.css b/activation/css/main.css new file mode 100644 index 0000000..b139fea --- /dev/null +++ b/activation/css/main.css @@ -0,0 +1,186 @@ +html, body { + height: 100%; + margin: 0; + padding: 0; +} +@media print +{ + html, body { font-size: 10pt !important; height: unset; } + table, caption, th, td { + font-size: 10pt !important; + /* border: 0.1pt solid lightgray !important; */ + border: none !important; + } + .no-print { display: none !important; height: 0; } + .no-print *{ display: none !important; height: 0; } + .print-only { display: block !important; } + .print-only *{ display: block !important; } +} +.print-only { display: none; } +.print-only *{ display: none; } + +p { margin-bottom: 0; } +.footer p { margin-top: 0; } + +/* body { font-size: 0.9em; } */ +.disabled { opacity: 0.3; } +label { font-weight: inherit; } +.controls input { width: 100%; } +table { margin: 0; padding: 0; border-spacing: 0; border-color: lightgray; } +caption, td, th { padding: 0 0.5em 0 0.5em; } +th { vertical-align: baseline; } +tbody tr:nth-child(2n) th, tbody tr.even th, +tbody tr:nth-child(2n) td, tbody tr.even td, +ul li:nth-child(2n), ol li:nth-child(2n) { background: inherit; /* background: none repeat scroll 0 0 #F3F3F9; */ } +table.tablesorter thead tr .headerSortable { + padding-right: 2em; /* space for sort arrows */ + cursor: pointer; +} +table.tablesorter thead tr .headerSortable::after { + content: " \25B4\25BE"; /* ▴▾ */ + opacity: 0.4; +} +table.tablesorter thead tr .headerSortable.headerSortUp::after { + content: " \25B2"; /* ▲ */ + opacity: 1; +} +table.tablesorter thead tr .headerSortable.headerSortDown::after { + content: " \25BC"; /* ▼ */ + opacity: 1; +} + +/* output markup */ +.error { color: red; } +p.disclaimer { color: darkred; font-size:1.2em; } +.activity_unusual { background-color:wheat; } +/* .activity_normal { background-color: lightred; } */ + +#id_chemical_formula { width: 30em; } + +div.cutoff { display: block; } +div.nocutoff { display: none; } +button.activity_button { float: right; } + +/* #wrapper { + height: 100%; + display: flex; + flex-direction: column; +} */ + +/* frame layout */ +#content-frame { + display: flex; + flex-direction: row; + width: 100%; +} + +#activation-frame { + width:30em; +} + +#help-frame { + position: relative; + flex: 1; + /* min-width:10em; max-width:40em; */ + overflow-y:scroll; +} + +#help-wrapper { + position: absolute; + padding-left:1em; + padding-right: 1em; + margin-right:0em; +} + +#help-wrapper .word-break { + word-break: break-all; +} + +#results-frame { + overflow: auto; + flex: 1; + border-top:#005ea2 1px solid; + border-bottom:#005ea2 1px solid; +} + +div.control-group { margin-left: 0.5em; vertical-align: bottom; } +/* div.control-group { height: 3ex; width: 15em; } */ +/* .help starts display:none so that size is initially zero. */ +.help { display:block; } +/*.help dl { margin-left: 30em; } +.help ol { margin-left: 30em; } +.help p { margin-left: 30em; } +*/ +.help h3 { margin-top: 0.25em; } +.help dd { margin-left: 1em; } +.help dt { margin-left: 0em; padding: 0.3em; font-weight: bold; } +.help ol { list-style-position: inside; padding-left: 0em; } +.help li { margin-left: 0em; margin-bottom: 1ex; } +.help div.bold { font-weight: bold; display: inline; } +.help div.entrytext { + display:inline; + font-weight:bold; + font-style:oblique; +} +.help div.example:before { content:"Example: "; } + +/* fading horizontal rule +modified from http://konigi.com/tools/css-techniques-horizontal-rules +*/ +.help hr { + width: 100%; + height: 1px; + margin: 2.4em 0; + border: none; + background: #ddd; + background-image: -webkit-gradient( + linear, + left bottom, + right bottom, + color-stop(0, rgb(255,255,255)), + color-stop(0.1, rgb(221,221,221)), + color-stop(0.9, rgb(221,221,221)), + color-stop(1, rgb(255,255,255)) + ); + background-image: -moz-linear-gradient( + left center, + rgb(255,255,255) 0%, + rgb(221,221,221) 10%, + rgb(221,221,221) 90%, + rgb(255,255,255) 100% + ); +} + +/* dictionary type: value on same line */ +dl.inline { + display: -ms-grid; -ms-grid-template-columns: max-content auto; + display: grid; grid-template-columns: max-content auto; +} +dl.inline dt { + -ms-grid-column-start: 1; + grid-column-start: 1; + padding: 0.1em; +} +dl.inline dd { + -ms-grid-column-start: 2; + grid-column-start: 2; + padding: 0.1em; margin-left: 0.5em; +} + +.panel { border-radius:0.6em; border: 2pt solid gray; margin: 0.5em; padding: 0.5em; } +.panel h3 { margin-top: -1em; margin-bottom: 0.3em; font-size: 1em; } +.panel h3 .text { background: white; margin-left: 1em; padding: 0 0.3em 0 0.3em; } +.panel { position: relative; } +.panel .btn { position:absolute; right: 1em; top: 0.75em;} +/* .panel .btn { position:absolute; top:1em; right:1em; } */ + +/* Keep constant baseline spacing even with superscript/subscript */ +sup, sub { + height: 0; + line-height: 1; + vertical-align: baseline; + _vertical-align: bottom; + position: relative; +} +sup { bottom: 1ex; } +sub { top: .5ex; } diff --git a/activation/css/nist-header.css b/activation/css/nist-header.css new file mode 100644 index 0000000..d75f88d --- /dev/null +++ b/activation/css/nist-header.css @@ -0,0 +1,56 @@ +@font-face { + font-family:"Source Sans Pro Web"; + font-style:normal; + font-weight:400; + font-display:fallback; + src: url(https://www.nist.gov/libraries/nist-component-library/dist/fonts/source-sans-pro/sourcesanspro-bold-webfont.woff2) format("woff2"), + url(https://www.nist.gov/libraries/nist-component-library/dist/fonts/source-sans-pro/sourcesanspro-regular-webfont.woff) format("woff"), + url(https://www.nist.gov/libraries/nist-component-library/dist/fonts/source-sans-pro/sourcesanspro-regular-webfont.ttf) format("truetype"); +} + +.ncnr-nist-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem; + background-color: #f5f5f5; + border-bottom: 1px solid #ddd; + background: url(https://www.nist.gov/libraries/nist-component-library/dist/img/pattern/bg_pattern.png) #006dbc; + position: relative; +} + +.ncnr-nist-header::before { + content: ""; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-image: linear-gradient(to right,transparent,#005ea2); +} + +.ncnr-nist-header h2 { + margin: 0; + font-family: Source Sans Pro Web; + font-size: 1.86rem; + line-height: 1.1; + text-decoration: none; + padding-left: 1rem; + text-transform: uppercase; + font-weight: 700; +} + +.ncnr-nist-header a { + text-decoration: none; + color: #FFF; + z-index: 2; + position: relative; +} + +.ncnr-nist-header img { + position: relative; + padding-right: 2rem; + max-width: 100px; + height: auto; + z-index: 2; +} diff --git a/activation/get_pyodide.sh b/activation/get_pyodide.sh new file mode 100755 index 0000000..49d23da --- /dev/null +++ b/activation/get_pyodide.sh @@ -0,0 +1,32 @@ +# !/bin/bash + +# Run in the activation directory (where this script lives) +cd "$(dirname "$0")" + +# Default version of pyodide to download if not set via environment variable +PYODIDE_VERSION=${PYODIDE_VERSION:-0.29.3} + +rm -rf pyodide +mkdir pyodide + +# Get the core pyodide files first (this is smaller and faster to download than the full version) +curl -L https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-core-${PYODIDE_VERSION}.tar.bz2 -o pyodide.tar.bz2 + tar -xjf pyodide.tar.bz2 -C ./pyodide --strip-components=1 + +# Download the full version to get the specific wheels we need (numpy, pytz, micropip) +curl -L https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-${PYODIDE_VERSION}.tar.bz2 -o pyodide_full.tar.bz2 + +# Extract only the core runtime + our specific wheels +tar -xjf pyodide_full.tar.bz2 -C ./pyodide --strip-components=1 \ + --wildcards --no-anchored \ + 'micropip-*.whl' 'numpy-*.whl' 'pytz-*.whl' 'pyparsing-*.whl' + +# Download the latest periodictable wheel from PyPI +pip3 download periodictable --no-deps --only-binary :all: -d ./pyodide/ + +# Write out the full wheel file name to a text file for use in the workflow +ls pyodide/periodictable-*.whl > periodictable_wheel_name.txt + +# Cleanup +rm -f pyodide.tar.bz2 +rm -f pyodide_full.tar.bz2 diff --git a/activation/index.html b/activation/index.html index 0a1bfea..c646860 100644 --- a/activation/index.html +++ b/activation/index.html @@ -4,267 +4,14 @@
+This calculator uses neutron cross sections to compute activation +of the sample given the mass in the sample and the time in the beam, +and to perform absorption and scattering calculations for samples on +slow neutron beamlines (energy below 325 meV, wavelength above 0.05 nm). +
+The chemical formula parser allows you to specify materials and mixtures. +Formulas are parsed with +periodictable +python package (Kienzle 2008). +
+ +Units: n/cm2/s
++ Provide the thermal flux equivalent for the pre-sample beam configuration + for the instrument. Because neutron capture cross sections are linear + above 0.5 Å for most isotopes, simply scale the flux by λ/1.798 Å, where + λ is the average wavelength at the sample weighted by spectral intensity. + For non-linear isotopes activation may be underestimated + (176Lu < 1.8 Å; 151Eu < 0.8 Å) + or overestimated (33S < 11 Å; 204Hg < 20 Å). +
++ The neutron activation calculation follows (Shleien 1998). + Activation is a function of isotope, not element. When + an element is used in a formula, the natural abundance of the individual + isotopes is used to determine the total activation. By default, the + activation calculator uses values from the IAEA + handbook (IAEA 1987), and the + scattering calculator uses the IUPAC 2021 atomic weights and isotope composition + database (CIAAW 2021). +
++ For very high fluences, e.g., more than 1016 n/cm2, the activation + equations give erroneous results because of the precision limitations. + If there is doubt simply do the calculation at a lower flux and + proportion the result. This will not work for the cascade reactions, + i.e., two neutron additions. +
++ Reaction = b : This is the beta produced daughter of an activated parent. + This is calculated only for the cases where the daughter is long lived + relative to the parent. The calculated activity is through the end of + exposure only. Contributions from the added decay of the parent after the + end of irradiation are left for the user to determine, but are usually + negligible for irradiations that are long relative to the parent halflife. +
+ +Calculation parameters are controlled by URL:
+Notes on calculation:
+Units: none
++ Samples in the rabbit tubes can be shielded with cadmium to reduce the thermal + flux while leaving the epithermal flux mostly unchanged. The cadmium ratio + determines the degree of reduction in the scattering cross sections, corresponding + to the reduced flux. This value is unitless. Use a value of 0 for beamline + experiments. +
+Units: none
++ When performing neutron activation analysis in a rabbit tube, the additional + fast neutron activations need to be determined. The thermal/fast ratio is + used to determine the fast neutron flux from the thermal flux equivalent for + the given rabbit tube. The resulting fast flux is (thermal flux)/(thermal/fast ratio). + This value is unitless. Use a value of 0 for beamline experiments. +
+Units: g, kg, mg or ug
++ The total neutron activation depends on the mass of the individual + isotopes in the sample and the total time in the beam. All activation + calculations assume a thin plate sample, with all parts of the sample + exposed to full flux during activation, and no self-shielding when + estimating the activation level outside the beam. +
+Units: h m s d w y
++ Exposure is the duration of the exposure at the given flux. Activation + will be accumulated over that time, with decay beginning the moment the + sample is activated. Time defaults to hours, but can be set to + hours, minutes, seconds, days, weeks or years by adding h, m, s, d, w, or y + to the value respectively. +
+Units: h m s d w y OR yyyy-mm-dd hh:mm:ss
++ The sample begins to decay immediately, even while it is being activated. + The decay field allows you to specify how long since the sample + was removed from the beam. The default is hours, but can be set to + hours, minutes, seconds, days, weeks or years by adding h, m, s, d, w, or y + to the value respectively. + We always compute the activation level when the sample is removed from the beam, + and at 1 hour, 1 day and 15 days post activation. +
++ Instead of saying how long the sample activation has decayed, you can use + the time that the sample was removed from the beam. Times are given as + year-month-day hour:minute:second. + Approximate times are allowed, such as 2010-03 for March, 2010. This is + equivalent to 2010-03-31 23:59:59, which is the end of March so that the + activation estimate will be conservative. This is the most activation + consistent with the sample being on the beam sometime in March, 2010. + Times are specified in US/Eastern. Add "Z" after the time of day to + indicate universal coordinated time (UTC), or add a timezone offset such + as "+01" for +1 hours in France in winter, when daylight savings time is + not in effect. +
+ +| If you type: | This is equivalent to: |
|---|---|
| 2 m | 2 minutes ago |
| 1 | 1 hour ago |
| 2.5w | 2 and a half weeks ago |
| 3 y | 3 years ago |
| 2015-01-02 21:45:00 | January 2, 2015 at 9:45 PM US/Eastern |
| 2010-03 | March 31, 2010 at 11:59:59 PM US/Eastern |
| 2010-7-5 12:23 | July 5, 2010 at 12:23:59 PM US/Eastern |
| 2015-01-02 21:45:00Z | January 2, 2015 at 9:45 PM UTC |
| 2015-01-02 21:45:00-0600 | January 2, 2015 at 9:45 PM US/Central |
| 2015-08-02 21:45:00-0500 | August 2, 2015 at 9:45 PM US/Central |
Units: g/cm3 or A3
++ Density is used to compute absorption, transmission and scattering. +
Units: cm
++ The material thickness in cm is used to determine sample transmission, + or how much beam will be absorbed by the sample or scattered incoherently. + Leave it at 1 cm if you do not need this information. +
+Units: Ang, meV or m/s
++ The energy of the source neutrons will affect the absorption cross section + and hence the penetration depth and sample attenuation. Energy can be + expressed as wavelength in Å, as energy in meV, or as neutron + velocity in m/s. + Neutron cross sections are tabulated + at 1.798 Å = 25.3 meV = 2200 m/s, with an assumed 1/v dependence for + the absorption cross section (Rauch 2003, + Sears 2006). +
+ For heavier isotopes (Cd, Hf, rare earths) and/or shorter wavelengths + (below 1 Å) there are neutron resonances + in the thermal range. For common rare-earth isotopes the energy-dependent + coherent and absorption cross sections tabulated in + Lynn and Seeger 1992 are used. + Incoherent scattering will be understimated for these elements. + Resonances for 113Cd and 180Ta are ignored. +
+ There is also a wavelength dependence for single phonon interactions which + gives rise to significant inelastic scattering for lighter isotopes (H, D) + and/or longer wavelengths (above 5 Å). This factor is both + temperature and material dependent and will not be included + in the scattering calculations. In particular, penetration length and + transmitted flux are going to be significantly overestimated. +
+Units: Ang, keV or Ka
++ X-ray absorption and scattering are computed from the energy dependent + atomic scattering factors (Henke 1993). + Energy can be expressed as wavelength in Å, as energy in keV, or + using an element name for the Kα emission line2 for + that element (Deslattes 2003). +
+5 g NaCl // 50 mL H2O@1
+ 5 um Si // 3 nm Cr // 8 nm Au
+