-
Notifications
You must be signed in to change notification settings - Fork 11
Material refactor plus integration tests #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mpiercy827
wants to merge
8
commits into
shawest:master
Choose a base branch
from
mpiercy827:material-refactor-plus-integration-tests
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
95f38b6
Pull material-related functionality into neucbot/material.py
mpiercy827 f61bc29
Add output files from current master branch for use as integration tests
mpiercy827 78adb59
Add integration tests script and incorporate into Github action
mpiercy827 8cc6c75
Test fixes
mpiercy827 00e0362
Fix stopping power calculation
mpiercy827 8f10ee3
Only populate stopping powers on material creation
mpiercy827 86594be
Ensure proper normalization of abundance and fractions
mpiercy827 a2b5d96
Update integration tests to eliminate floating point imprecision errors
mpiercy827 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| from bisect import bisect | ||
|
|
||
| from neucbot import elements | ||
|
|
||
| N_A = 6.0221409e23 | ||
|
|
||
|
|
||
| class Isotope: | ||
| # self.fraction should be a number between 0 and 1 | ||
| def __init__(self, element, mass_number, fraction): | ||
| self.element = element | ||
| self.mass_number = int(mass_number) | ||
| self.fraction = float(fraction) | ||
|
|
||
| def material_term(self): | ||
| return (N_A * self.fraction) / self.mass_number | ||
|
|
||
|
|
||
| class StoppingPowerList: | ||
| def __init__(self, element_symbol): | ||
| self.element_symbol = element_symbol | ||
| self.stopping_powers = {} | ||
|
|
||
| def load_file(self): | ||
| file_path = f"./Data/StoppingPowers/{self.element_symbol.lower()}.dat" | ||
| file = open(file_path) | ||
|
|
||
| for data in [ | ||
| line.split() for line in file.readlines() if not line.startswith("#") | ||
| ]: | ||
| energy = float(data[0]) | ||
| units = str(data[1]) | ||
| stopping_power = float(data[2]) + float(data[3]) | ||
|
|
||
| if units == "keV": | ||
| energy /= 1000 | ||
|
|
||
| self.stopping_powers[energy] = stopping_power | ||
|
|
||
| # Use binary search to find energy in log(N) time | ||
| def for_alpha(self, alpha_energy): | ||
| energy_intervals = list(self.stopping_powers.keys()) | ||
| min_energy = energy_intervals[0] | ||
| max_energy = energy_intervals[-1] | ||
|
|
||
| if alpha_energy < min_energy: | ||
| return self.stopping_powers[min_energy] | ||
| elif alpha_energy > max_energy: | ||
| return self.stopping_powers[max_energy] | ||
|
|
||
| range_end = bisect(energy_intervals, alpha_energy) | ||
| range_start = range_end - 1 | ||
|
|
||
| energy_start = energy_intervals[range_start] | ||
| energy_end = energy_intervals[range_end] | ||
| energy_diff = (alpha_energy - energy_start) / (energy_end - energy_start) | ||
|
|
||
| stop_power_start = self.stopping_powers[energy_start] | ||
| stop_power_end = self.stopping_powers[energy_end] | ||
|
|
||
| return (stop_power_end - stop_power_start) * energy_diff + stop_power_start | ||
|
|
||
|
|
||
| class Composition: | ||
| @classmethod | ||
| def from_file(cls, file_path): | ||
| file = open(file_path) | ||
|
|
||
| composition = cls() | ||
|
|
||
| for material in [ | ||
| line.split() for line in file.readlines() if not line.startswith("#") | ||
| ]: | ||
| if len(material) < 3: | ||
| continue | ||
|
|
||
| element = elements.Element(material[0]) | ||
| mass_number = int(material[1]) | ||
| fraction = float(material[2]) | ||
|
|
||
| # If a single mass number isn't specified, use all isotopes | ||
| # along with their natural abundances | ||
| if mass_number == 0: | ||
| for isotope in element.isotopes(): | ||
| composition.add( | ||
| Isotope( | ||
| element, | ||
| isotope, | ||
| fraction * element.abundance(isotope) / 100.0, | ||
| ) | ||
| ) | ||
|
|
||
| # Otherwise, if a single mass number is provided, | ||
| # use the fraction provided | ||
| else: | ||
| composition.add( | ||
| Isotope( | ||
| element, | ||
| mass_number, | ||
| fraction / 100.0, | ||
| ) | ||
| ) | ||
|
|
||
| composition.normalize() | ||
| composition.populate_stopping_powers() | ||
|
|
||
| return composition | ||
|
|
||
| def __init__(self): | ||
| self.materials = [] | ||
| self.fractions = {} | ||
| self.stopping_powers = {} | ||
|
|
||
| def normalize(self): | ||
| norm = 0 | ||
|
|
||
| for material in self.materials: | ||
| norm += material.fraction | ||
|
|
||
| for material in self.materials: | ||
| material.fraction /= norm | ||
|
|
||
| # Computes the fraction of this element in the overall material, | ||
| # grouping isotopes with the same Z | ||
| symbol = material.element.symbol | ||
| self.fractions[symbol] = self.fractions.get(symbol, 0) + material.fraction | ||
|
|
||
| def populate_stopping_powers(self): | ||
| # Populates stopping powers from ./Data/StoppingPowers once so that | ||
| # they don't need to be populated for every energy step | ||
| for element in self.fractions: | ||
| stop_power_list = StoppingPowerList(element) | ||
| stop_power_list.load_file() | ||
|
|
||
| self.stopping_powers[element] = stop_power_list | ||
|
|
||
| def empty(self): | ||
| return len(self.materials) == 0 | ||
|
|
||
| def add(self, material): | ||
| self.materials.append(material) | ||
|
|
||
| # Expects an alpha energy in units of MeV | ||
| def stopping_power(self, e_alpha): | ||
| total_stopping_power = 0 | ||
|
|
||
| for element, fraction in self.fractions.items(): | ||
| element_stop_power = self.stopping_powers[element].for_alpha(e_alpha) | ||
|
|
||
| total_stopping_power += element_stop_power * fraction | ||
|
|
||
| return total_stopping_power |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #!/bin/bash | ||
| set -e | ||
|
|
||
| python3 ./neucbot.py -m Materials/Acrylic.dat -c Chains/Th232Chain.dat -d v2 -o tmp-acrylic-th232-chain.txt | ||
| diff tmp-acrylic-th232-chain.txt tests/integration_tests/acrylic-th232-chain.txt | ||
| rm tmp-acrylic-th232-chain.txt | ||
|
|
||
| python3 ./neucbot.py -m Materials/Acrylic.dat -l AlphaLists/Rn220Alphas.dat -d v2 -o tmp-acrylic-rn220-alphalist.txt | ||
| diff tmp-acrylic-rn220-alphalist.txt tests/integration_tests/acrylic-rn220-alphalist.txt | ||
| rm tmp-acrylic-rn220-alphalist.txt | ||
|
|
||
| python3 ./neucbot.py -m Materials/Acrylic.dat -l AlphaLists/Bi212Alphas.dat -d v2 -o tmp-acrylic-bi212-alphalist.txt | ||
| diff tmp-acrylic-bi212-alphalist.txt tests/integration_tests/acrylic-bi212-alphalist.txt | ||
| rm tmp-acrylic-bi212-alphalist.txt |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.