def test_efficiency_calibration(self): """Do efficiency calibration of detector to spectrum of calibrated 152-Eu source""" # test are run sorted by the string representations of the test methods; we need this to be run first if self.energy_calibration is None: self.test_energy_calibration() # generate expected peaks from source specs Eu152_expected = source_to_dict(self.Eu152_source_specs, info='lines') efficiency_calib_bkg = sp.interpolate_bkg( counts=self.Eu152_spectrum[1]) efficiency_calib_peaks = sp.fit_spectrum( counts=self.Eu152_spectrum[1], energy_cal=self.energy_calibration['func'], expected_accuracy=self. accuracy, # self.energy_calibration['accuracy'] expected_peaks=Eu152_expected, bkg=efficiency_calib_bkg) # check whether all peaks have been found self.assertListEqual(sorted(efficiency_calib_peaks.keys()), sorted(Eu152_expected.keys())) self.efficiency_calibration = sp.do_efficiency_calibration( observed_peaks=efficiency_calib_peaks, source_specs=self.Eu152_source_specs) # 50 % error on fit parameters self.assertTrue( all(self.efficiency_calibration['perr'] / self.efficiency_calibration['popt'] <= 0.5))
def test_dose(self): """Testing the dose calculations on the example spectrum""" # test are run sorted by the string representations of the test methods; we need this to be run first if self.energy_calibration is None: self.test_energy_calibration() # test are run sorted by the string representations of the test methods; we need this to be run first if self.efficiency_calibration is None: self.test_efficiency_calibration() peaks_sample, bkg_sample = sp.fit_spectrum( counts=self.sample_spectrum[1], energy_cal=self.energy_calibration['func'], efficiency_cal=self.efficiency_calibration['func'], t_spec=self.t_sample) dose = sp.get_dose(peaks_sample, distance=50, time=2000) self.assertTrue(np.isclose(dose['nominal'], 1.1330667863561383)) self.assertTrue(np.isclose(dose['sigma'], 0.03766586624214202)) self.assertTrue(dose['unit'] == 'uSv') dose = sp.get_dose(peaks_sample, distance=1) self.assertTrue(np.isclose(dose['nominal'], 1.8437455480798448)) self.assertTrue(np.isclose(dose['sigma'], 0.05874337083851746)) self.assertTrue(dose['unit'] == 'uSv/h') selected_peaks = select_peaks(['65_Zn', '48_V', '7_Be'], peaks_sample) self.assertEqual(len(selected_peaks), 4) selected_dose = sp.get_dose(selected_peaks, distance=50, time=2000) self.assertTrue( np.isclose(selected_dose['nominal'], 0.5343614796430098)) selected_dose_time_1 = sp.get_dose(selected_peaks, distance=50, time=1e6)['nominal'] selected_dose_time_2 = sp.get_dose(selected_peaks, distance=50, time=1e7)['nominal'] self.assertTrue(np.isclose(selected_dose_time_1, selected_dose_time_2))
def test_energy_calibration(self): """Do energy calibration of detector channels to spectrum of 152-Eu source""" energy_calib_bkg = sp.interpolate_bkg(counts=self.Eu152_spectrum[1]) energy_calib_peaks = sp.fit_spectrum( counts=self.Eu152_spectrum[1], expected_peaks=self.energy_calib_peaks['channel'], bkg=energy_calib_bkg) # check whether all peaks have been found self.assertListEqual(sorted(energy_calib_peaks.keys()), sorted(self.energy_calib_peaks['channel'].keys())) self.energy_calibration = sp.do_energy_calibration( observed_peaks=energy_calib_peaks, peak_energies=self.energy_calib_peaks['energy']) # 50 % error on fit parameters self.assertTrue( all(self.energy_calibration['perr'] / self.energy_calibration['popt'] <= 0.5))
def test_benchmark(self): """ Do a benchmark of the software with two, calibrated sources; 22-Na and 133-Ba. The expected peaks of both spectra are fitted to first benchmark the energy calibration with the peak positions. Then the integrated and scaled activity is compared to the theoretically expected activity to benchmark the efficiency calibration as well as the fitting and background subtraction. Overall, a reconstruction accuracy of above 90 % is achieved for both sources (after approx. 10 minute measurement) The 22-Na source has one line/peak => 22-Na activity is (93.4 +- 2.7)% accurately measured The 133-Ba source has 5 lines/peaks => 133-Ba activity is (97.0 +- 1.2)% accurately measured """ # test are run sorted by the string representations of the test methods; we need this to be run first if self.energy_calibration is None: self.test_energy_calibration() # test are run sorted by the string representations of the test methods; we need this to be run first if self.efficiency_calibration is None: self.test_efficiency_calibration() # test energy calibration by applying to Na22 and Ba133 spectra # generate expected peaks from source specs Na22_expected = source_to_dict(self.Na22_source_specs, info='lines') # fit spectrum of source Na22_peaks, Na22_bkg = sp.fit_spectrum( counts=self.Na22_spectrum[1], energy_cal=self.energy_calibration['func'], efficiency_cal=self.efficiency_calibration['func'], t_spec=self.t_Na22, expected_accuracy=self.accuracy ) # self.energy_calibration['accuracy'] # check whether all expected peaks have been found from library self.assertTrue(all(ep in Na22_peaks for ep in Na22_expected.keys())) # check whether all activities are in Bq self.assertTrue( all('normalized' == Na22_peaks[p]['activity']['type'] for p in Na22_peaks)) # check whether all activities are calibrated for efficiency self.assertTrue( all(Na22_peaks[p]['activity']['calibrated'] for p in Na22_peaks)) # check whether all peaks are at correct energies within 1 per mille accuracy for na22_peak in Na22_peaks: if na22_peak in Na22_expected: low, high = (x * Na22_expected[na22_peak] for x in (1 - self.accuracy, 1 + self.accuracy)) self.assertTrue( low <= Na22_peaks[na22_peak]['peak_fit']['popt'][0] <= high ) # check for correct activity from library Na22_activity_meas = sp.get_activity(Na22_peaks) Na22_activity_theo = decay_law( t=self.Na22_source_specs['timestamp_measurement'] - self.Na22_source_specs['timestamp_calibration'], x0=np.array(self.Na22_source_specs['activity']), half_life=self.Na22_source_specs['half_life']) # check to see at least 90% of the expected activity; only order of magnitude relevant self.assertTrue(0.9 <= Na22_activity_meas['22_Na']['nominal'] / Na22_activity_theo[0] <= 1.0) # generate expected peaks and probabilities from source specs Ba133_expected = source_to_dict(self.Ba133_source_specs, info='lines') # fit spectrum of source Ba133_peaks, Ba133_bkg = sp.fit_spectrum( counts=self.Ba133_spectrum[1], energy_cal=self.energy_calibration['func'], efficiency_cal=self.efficiency_calibration['func'], t_spec=self.t_Ba133, expected_accuracy=self.accuracy ) # self.energy_calibration['accuracy'] # check whether all expected peaks have been found from library self.assertTrue(all(ep in Ba133_peaks for ep in Ba133_expected.keys())) # check whether all activities are in Bq self.assertTrue( all('normalized' == Ba133_peaks[p]['activity']['type'] for p in Ba133_peaks)) # check whether all activities are calibrated for efficiency self.assertTrue( all(Ba133_peaks[p]['activity']['calibrated'] for p in Ba133_peaks)) # check whether all peaks are at correct energies within 1 per mill accuracy for ba133_peak in Ba133_peaks: if ba133_peak in Ba133_expected: low, high = (x * Ba133_expected[ba133_peak] for x in (1 - self.accuracy, 1 + self.accuracy)) self.assertTrue( low <= Ba133_peaks[ba133_peak]['peak_fit']['popt'][0] <= high, msg=str(self.energy_calibration['accuracy'])) # check for correct activity Ba133_activity_meas = sp.get_activity(Ba133_peaks) Ba133_activity_theo = decay_law( t=self.Ba133_source_specs['timestamp_measurement'] - self.Ba133_source_specs['timestamp_calibration'], x0=np.array(self.Ba133_source_specs['activity']), half_life=self.Ba133_source_specs['half_life']) # check to see at least 90% of the expected activity; only order of magnitude relevant self.assertTrue(0.9 <= Ba133_activity_meas['133_Ba']['nominal'] / Ba133_activity_theo[0] <= 1.0)