radiation 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +17 -17
- data/.rspec +1 -1
- data/CHANGELOG.md +12 -12
- data/Gemfile +5 -5
- data/LICENSE.txt +22 -22
- data/README.md +45 -45
- data/Rakefile +6 -6
- data/data/iaea-xgamma.json +2615 -0
- data/lib/radiation/cli.rb +6 -1
- data/lib/radiation/resource/iaea.rb +28 -0
- data/lib/radiation/resource/internal.rb +10 -4
- data/lib/radiation/source.rb +5 -2
- data/lib/radiation/spectrum.rb +35 -23
- data/lib/radiation/version.rb +1 -1
- data/lib/radiation.rb +1 -0
- data/radiation.gemspec +32 -32
- data/samples/B0-Ra226.xml +4721 -4721
- data/spec/radiation_spec.rb +3 -1
- metadata +4 -2
data/lib/radiation/cli.rb
CHANGED
|
@@ -19,6 +19,11 @@ class CLI < Thor
|
|
|
19
19
|
puts Radiation::Source.new(nuclide: nuclide, resource: resource).intensities.collect{|l| [l[:energy].value, l[:energy].delta, l[:intensity].value, l[:intensity].delta].join("\t") }
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
desc "resources", "List available data resources"
|
|
23
|
+
def resources
|
|
24
|
+
puts Radiation::Source.new.resources
|
|
25
|
+
end
|
|
26
|
+
|
|
22
27
|
option :resource
|
|
23
28
|
desc "calibrate NUCLIDE SPECTRUM.xml", "calibrate a spectrum"
|
|
24
29
|
long_desc <<-LONGDESC
|
|
@@ -50,7 +55,7 @@ class CLI < Thor
|
|
|
50
55
|
source = Radiation::Source.new(nuclide: nuclide, resource: resource)
|
|
51
56
|
spectrum = Radiation::Spectrum.new(source: source ).parse_hdtv(file)
|
|
52
57
|
puts ["E_ɣ", "I_ɣ", "ΔI_ɣ", "e", "Δe"].join("\t")
|
|
53
|
-
spectrum.calibrate.efficiencies.select{|p| p[:intensity] > mini}.sort_by{|k| k[:energy]}.each do |p|
|
|
58
|
+
spectrum.calibrate.efficiencies.peaks.select{|p| p[:intensity] > mini}.sort_by{|k| k[:energy]}.each do |p|
|
|
54
59
|
puts [ p[:energy].to_f.round(1), p[:intensity].value, p[:intensity].delta, p[:efficiency].value.round(1), p[:efficiency].delta.round(1) ].join("\t")
|
|
55
60
|
end
|
|
56
61
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Radiation::Resource
|
|
5
|
+
class IAEA < Base
|
|
6
|
+
# FIXME: Better path creation
|
|
7
|
+
PATH = File.join(File.dirname(__FILE__), "../../../data")
|
|
8
|
+
FILENAME = "iaea-xgamma.json"
|
|
9
|
+
|
|
10
|
+
def fetch(nuclide)
|
|
11
|
+
@nuclide = nuclide
|
|
12
|
+
begin
|
|
13
|
+
@data = load_data(@nuclide)
|
|
14
|
+
# FIXME: Better conversion from x, x_uncertainty to pm
|
|
15
|
+
@data[:transitions].collect!{|t| { :energy => t[:energy].to_f.pm(t[:energy_uncertainty].to_f), :intensity => t[:intensity].to_f.pm(t[:intensity_uncertainty].to_f)} }
|
|
16
|
+
rescue
|
|
17
|
+
raise "No Data for #{@nuclide}"
|
|
18
|
+
end
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
def load_data(nuclide)
|
|
24
|
+
JSON.parse( IO.read("#{PATH}/#{FILENAME}"), {:symbolize_names => true} ).select{|n| n[:nuclide] == nuclide}.first
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -3,18 +3,24 @@ require 'csv'
|
|
|
3
3
|
|
|
4
4
|
module Radiation::Resource
|
|
5
5
|
class Internal < Base
|
|
6
|
-
|
|
6
|
+
# FIXME: Better path creation
|
|
7
|
+
PATH = File.join(File.dirname(__FILE__), "../../../data")
|
|
8
|
+
|
|
7
9
|
def fetch(nuclide)
|
|
8
10
|
@nuclide = nuclide
|
|
9
11
|
begin
|
|
10
|
-
path = File.join(File.dirname(__FILE__), "../../../data")
|
|
11
12
|
@data[:nuclide] = @nuclide.to_s
|
|
12
|
-
@data[:transitions] =
|
|
13
|
+
@data[:transitions] = load_data(@nuclide).collect{|row| {:energy => row[0].pm(0), :intensity => row[1].pm(row[2])} }
|
|
13
14
|
rescue
|
|
14
15
|
raise "No Data for #{nuclide}"
|
|
15
16
|
end
|
|
16
17
|
self
|
|
17
18
|
end
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
def load_data(nuclide)
|
|
22
|
+
CSV.read("#{PATH}/#{nuclide}.csv", {col_sep: ';', converters: :numeric})
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
end
|
|
20
26
|
end
|
data/lib/radiation/source.rb
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
-
require 'combinatorics'
|
|
3
|
-
|
|
4
2
|
module Radiation
|
|
5
3
|
class Source
|
|
6
4
|
attr_reader :resource, :nuclide, :halflife, :reference, :description, :transitions
|
|
@@ -17,12 +15,17 @@ module Radiation
|
|
|
17
15
|
raise "Nuclide: #{@nuclide} is not valid." unless is_nuclide?(@nuclide)
|
|
18
16
|
data = case @resource
|
|
19
17
|
when "internal" then Radiation::Resource::Internal.new.fetch(@nuclide).data
|
|
18
|
+
when "iaea" then Radiation::Resource::IAEA.new.fetch(@nuclide).data
|
|
20
19
|
when "nucleide.org" then Radiation::Resource::Nucleideorg.new.fetch(@nuclide).data
|
|
21
20
|
else raise "Unknown Datasource"
|
|
22
21
|
end
|
|
23
22
|
build(data)
|
|
24
23
|
return self
|
|
25
24
|
end
|
|
25
|
+
|
|
26
|
+
def resources
|
|
27
|
+
["internal", "iaea", "nucleide.org"]
|
|
28
|
+
end
|
|
26
29
|
|
|
27
30
|
def read(options={})
|
|
28
31
|
@resource = "external"
|
data/lib/radiation/spectrum.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
require 'combinatorics'
|
|
2
3
|
require "linefit"
|
|
3
4
|
require "plusminus"
|
|
4
5
|
require "xmlsimple"
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
module Radiation
|
|
7
8
|
class Spectrum
|
|
8
9
|
attr_accessor :peaks, :source, :calibration
|
|
9
10
|
|
|
@@ -20,30 +21,14 @@ require "xmlsimple"
|
|
|
20
21
|
|
|
21
22
|
if @peaks.select{|p| p.key?(:channel) and p.key?(:energy)}.empty?
|
|
22
23
|
if @calibration == [0,1] and @source.nil?
|
|
23
|
-
raise "No channel <-> energy associations. Specify a Source or a
|
|
24
|
+
raise "No channel <-> energy associations. Specify a Source or a preliminary calibration to improve"
|
|
24
25
|
else
|
|
25
26
|
self.guess_calibration
|
|
26
27
|
end
|
|
27
28
|
self.match_channels
|
|
28
29
|
end
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
x = mpeaks.collect{|p| p[:channel]}
|
|
32
|
-
y = mpeaks.collect{|p| p[:energy]}
|
|
33
|
-
lineFit = LineFit.new
|
|
34
|
-
lineFit.setData(x,y)
|
|
35
|
-
intercept, slope = lineFit.coefficients
|
|
36
|
-
varianceIntercept, varianceSlope = lineFit.varianceOfEstimates
|
|
37
|
-
@calibration = [intercept.pm(Math.sqrt(varianceIntercept)), slope.pm(Math.sqrt(varianceSlope))]
|
|
38
|
-
return self
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def match_channels(energies=@source.energies, rounding=4)
|
|
42
|
-
@peaks.each do |peak|
|
|
43
|
-
energies.each do |energy|
|
|
44
|
-
peak[:energy] = energy if channel_energy(peak[:channel]).to_f.approx_equal?(energy, rounding)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
30
|
+
|
|
31
|
+
@calibration = apply_linefit(@peaks)
|
|
47
32
|
return self
|
|
48
33
|
end
|
|
49
34
|
|
|
@@ -70,22 +55,49 @@ require "xmlsimple"
|
|
|
70
55
|
end
|
|
71
56
|
|
|
72
57
|
def efficiencies(rounding=4)
|
|
58
|
+
self.match_channels
|
|
59
|
+
@peaks.select{|p| p.key?(:intensity) and p.key?(:counts)}.each{|p| p[:efficiency] = channel_efficiency(p)}
|
|
60
|
+
return self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def match_channels(source=@source, rounding=4)
|
|
73
64
|
@peaks.each do |peak|
|
|
74
|
-
|
|
65
|
+
source.transitions.each do |transition|
|
|
75
66
|
if channel_energy(peak[:channel]).to_f.approx_equal?(transition[:energy], rounding)
|
|
76
67
|
peak[:energy] = transition[:energy]
|
|
77
68
|
peak[:intensity] = transition[:intensity] if transition[:intensity] > 0
|
|
78
69
|
end
|
|
79
70
|
end
|
|
80
71
|
end
|
|
81
|
-
|
|
72
|
+
return self
|
|
82
73
|
end
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
|
|
85
76
|
def channel_efficiency(peak)
|
|
86
77
|
peak[:counts]/peak[:intensity]
|
|
87
78
|
end
|
|
88
79
|
|
|
80
|
+
private
|
|
81
|
+
def apply_linefit(peaks)
|
|
82
|
+
#calibrate using linefit
|
|
83
|
+
mpeaks = peaks.delete_if{|p| p[:energy] == nil}
|
|
84
|
+
x = mpeaks.collect{|p| p[:channel]}
|
|
85
|
+
y = mpeaks.collect{|p| p[:energy]}
|
|
86
|
+
lineFit = LineFit.new
|
|
87
|
+
|
|
88
|
+
# Use weighted calibration when possible
|
|
89
|
+
if mpeaks.count{|p| p[:intensity] and p[:intensity] > 0} == mpeaks.count
|
|
90
|
+
weights = mpeaks.collect{|p| p[:intensity].nil? ? 0 : p[:intensity]}
|
|
91
|
+
lineFit.setData(x,y,weights)
|
|
92
|
+
else
|
|
93
|
+
lineFit.setData(x,y)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
intercept, slope = lineFit.coefficients
|
|
97
|
+
varianceIntercept, varianceSlope = lineFit.varianceOfEstimates
|
|
98
|
+
return [intercept.pm(Math.sqrt(varianceIntercept.abs)), slope.pm(Math.sqrt(varianceSlope.abs))]
|
|
99
|
+
end
|
|
100
|
+
|
|
89
101
|
end
|
|
90
102
|
end
|
|
91
103
|
|
data/lib/radiation/version.rb
CHANGED
data/lib/radiation.rb
CHANGED
data/radiation.gemspec
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require 'radiation/version'
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "radiation"
|
|
8
|
-
spec.version = Radiation::VERSION
|
|
9
|
-
spec.authors = ["Jan Mayer"]
|
|
10
|
-
spec.email = ["jan.mayer@ikp.uni-koeln.de"]
|
|
11
|
-
spec.description = %q{Decay Radiation}
|
|
12
|
-
spec.summary = %q{This gem provides easy access to energies and intensities from the decay of radioactive nuclei}
|
|
13
|
-
spec.homepage = "https://github.com/janmayer/radiation"
|
|
14
|
-
spec.license = "MIT"
|
|
15
|
-
|
|
16
|
-
spec.files = `git ls-files`.split($/)
|
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
-
spec.require_paths = ["lib"]
|
|
20
|
-
|
|
21
|
-
spec.add_dependency "plusminus"
|
|
22
|
-
spec.add_dependency "open-uri-cached"
|
|
23
|
-
spec.add_dependency "combinatorics"
|
|
24
|
-
spec.add_dependency "linefit"
|
|
25
|
-
spec.add_dependency "xml-simple"
|
|
26
|
-
spec.add_dependency "thor"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
|
30
|
-
spec.add_development_dependency "rake"
|
|
31
|
-
spec.add_development_dependency "rspec"
|
|
32
|
-
end
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'radiation/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "radiation"
|
|
8
|
+
spec.version = Radiation::VERSION
|
|
9
|
+
spec.authors = ["Jan Mayer"]
|
|
10
|
+
spec.email = ["jan.mayer@ikp.uni-koeln.de"]
|
|
11
|
+
spec.description = %q{Decay Radiation}
|
|
12
|
+
spec.summary = %q{This gem provides easy access to energies and intensities from the decay of radioactive nuclei}
|
|
13
|
+
spec.homepage = "https://github.com/janmayer/radiation"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_dependency "plusminus"
|
|
22
|
+
spec.add_dependency "open-uri-cached"
|
|
23
|
+
spec.add_dependency "combinatorics"
|
|
24
|
+
spec.add_dependency "linefit"
|
|
25
|
+
spec.add_dependency "xml-simple"
|
|
26
|
+
spec.add_dependency "thor"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
|
30
|
+
spec.add_development_dependency "rake"
|
|
31
|
+
spec.add_development_dependency "rspec"
|
|
32
|
+
end
|