Skip to content

Commit df2172a

Browse files
committed
Merge branch 'feature/CAMIO'
2 parents c984607 + 72c8b9c commit df2172a

File tree

9 files changed

+2828
-925
lines changed

9 files changed

+2828
-925
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ option( SpecUtils_BUILD_UNIT_TESTS "Builds unit tests" OFF )
1919
option( SpecUtils_BUILD_FUZZING_TESTS "Builds fuzzing tests, requires clang" OFF )
2020
option( SpecUtils_BUILD_REGRESSION_TEST "Creates executable to perform interactive regression test" OFF )
2121
option( SpecUtils_BUILD_EXAMPLE "Builds example SpecUtil applications" OFF )
22+
option( SpecUtils_JAVA_SWIG "Creates swig/java bindings to the c++ code" OFF )
23+
option( SpecUtils_C_BINDINGS "Creates C bindings to the c++ code" OFF )
2224
option( SpecUtils_INJA_TEMPLATES "Creates inja template interface" OFF )
2325
option( SpecUtils_USE_SIMD "Use SIMD operations; i386/x64 only right now, and very alpha, and extremely minimally used" OFF )
2426
option( SpecUtils_ENABLE_EQUALITY_CHECKS "Enables the equal_enough(...) functions for comparing two spectrum files." OFF ) #code size is only reason to default to off, I think
@@ -129,6 +131,7 @@ set( sources
129131
src/DateTime.cpp
130132
src/ParseUtils.cpp
131133
src/SpecFile_location.cpp
134+
src/CAMIO.cpp
132135
README.md
133136
)
134137

@@ -145,6 +148,7 @@ set( headers
145148
SpecUtils/ParseUtils.h
146149
SpecUtils/SpecFile_location.h
147150
SpecUtils/RapidXmlUtils.hpp
151+
SpecUtils/CAMIO.h
148152
)
149153

150154
if( SpecUtils_INJA_TEMPLATES )
@@ -328,7 +332,7 @@ if( SpecUtils_USE_FROM_CHARS )
328332
)
329333
else(SpecUtils_USE_FROM_CHARS)
330334
set_target_properties( SpecUtils PROPERTIES
331-
CXX_STANDARD 11
335+
CXX_STANDARD 17
332336
CXX_STANDARD_REQUIRED YES
333337
CXX_EXTENSIONS NO
334338
)

SpecUtils/CAMIO.h

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
#pragma once
2+
3+
/**
4+
SpecUtils: a library to parse, save, and manipulate gamma spectrum data files.
5+
Copyright (C) 2016 William Johnson
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#include <vector>
23+
#include <string>
24+
#include <cstdint>
25+
#include <map>
26+
#include <memory>
27+
#include <chrono>
28+
#include "DateTime.h"
29+
30+
namespace
31+
{
32+
typedef unsigned char byte_type;
33+
}
34+
35+
namespace CAMInputOutput
36+
{
37+
38+
// Structs
39+
struct EfficiencyPoint {
40+
int Index;
41+
float Energy;
42+
float Efficiency;
43+
float EfficiencyUncertainty;
44+
};
45+
46+
struct Peak {
47+
float Energy;
48+
/** The channel number of the peak. */
49+
float Centroid;
50+
float CentroidUncertainty;
51+
float FullWidthAtHalfMaximum;
52+
float LowTail;
53+
float Area;
54+
float AreaUncertainty;
55+
float Continuum;
56+
float CriticalLevel;
57+
float CountRate;
58+
float CountRateUncertainty;
59+
int LeftChannel;
60+
int RightChannel;
61+
62+
Peak() = default;
63+
Peak(float energy, float centrd, float centrdUnc, float fwhm, float lowTail,
64+
float area, float areaUnc, float continuum, float critialLevel,
65+
float cntRate, float cntRateUnc, int leftChan, int rightChan);
66+
};
67+
68+
struct Nuclide {
69+
std::string Name;
70+
float HalfLife = 0.;
71+
float HalfLifeUncertainty = 0.;
72+
std::string HalfLifeUnit;
73+
int Index = -1;
74+
int AtomicNumber = 0;
75+
std::string ElementSymbol;
76+
std::string Metastable;
77+
78+
// all in uCi, default Genie unit
79+
double Activity = 0.;
80+
double ActivityUnc = 0.;
81+
double MDA = 0.;
82+
83+
84+
Nuclide() = default;
85+
Nuclide(const std::string& name, float halfLife, float halfLifeUnc,
86+
const std::string& halfLifeUnit, int nucNo,
87+
double activity, double activityUnc, double mda);
88+
89+
inline bool operator==(const Nuclide & other) const
90+
{
91+
return Name == other.Name;
92+
}
93+
94+
95+
};
96+
97+
struct Line {
98+
float Energy = 0.;
99+
float EnergyUncertainty = 0.;
100+
float Abundance = 0.;
101+
float AbundanceUncertainty = 0.;
102+
bool IsKeyLine = false;
103+
int NuclideIndex = -1;
104+
bool NoWeightMean = false;
105+
106+
double LineActivity = 0.;
107+
double LineActivityUnceratinty = 0.;
108+
float LineEfficiency = 0. ;
109+
float LineEfficiencyUncertainty = 0.;
110+
double LineMDA = 0.;
111+
112+
Line() = default;
113+
Line(float energy, float energyUnc, float abundance, float abundanceUnc,
114+
int nucNo, bool key = false, bool noWgtMean = false, double lineAct = 0.,
115+
double lineActUnc = 0., float lineEff = 0., float lineEffUnc = 0., double lineMDA = 0.);
116+
};
117+
118+
struct DetInfo
119+
{
120+
std::string Type; //DETTYPE
121+
std::string Name; //DETNAME
122+
std::string SerialNo; //MCAID
123+
std::string MCAType; // MCATYPE
124+
125+
DetInfo() = default;
126+
DetInfo(std::string type, std::string name, std::string serial_no, std::string mca_type);
127+
};
128+
129+
// Main CAMIO class
130+
class CAMIO {
131+
public:
132+
enum class CAMBlock : uint32_t {
133+
ACQP = 0x00012000,
134+
SAMP = 0x00012001,
135+
GEOM = 0x00012002,
136+
PROC = 0x00012003,
137+
DISP = 0x00012004,
138+
SPEC = 0x00012005, //also known as DATA
139+
PEAK = 0x00012006,
140+
NUCL = 0x00012007,
141+
NLINES = 0x00012008
142+
};
143+
144+
enum class RecordSize : uint16_t {
145+
ACQP = 0x0440,
146+
NUCL = 0x023B,
147+
NLINES = 0x0085
148+
};
149+
150+
enum class BlockSize : uint16_t {
151+
ACQP = 0x800,
152+
PROC = 0x800,
153+
NUCL = 0x4800,
154+
NLINES = 0x4200,
155+
SAMP = 0x0A00
156+
};
157+
158+
enum class PeakParameterLocation : uint8_t {
159+
Energy = 0x0,
160+
Centroid = 0x40,
161+
CentroidUncertainty = 0x44,
162+
FullWidthAtHalfMaximum = 0x10,
163+
LowTail = 0x50,
164+
Area = 0x34,
165+
AreaUncertainty = 0x84,
166+
Continuum = 0x0C,
167+
CriticalLevel = 0x0D1,
168+
CountRate = 0x18,
169+
CountRateUncertainty = 0x1C,
170+
LeftChannel = 0x06,
171+
Width = 0x0A
172+
};
173+
174+
enum class EfficiencyPointParameterLocation : uint8_t {
175+
Energy = 0x01,
176+
Efficiency = 0x05,
177+
EfficiencyUncertainty = 0x09
178+
};
179+
180+
enum NuclideParameterLocation : uint8_t
181+
{
182+
Name = 0x03,
183+
HalfLife = 0x1B,
184+
HalfLifeUncertainty = 0x89,
185+
HalfLifeUnit = 0x61,
186+
MeanActivity = 0x57,
187+
MeanActivityUnceratinty = 0x69,
188+
NuclideMDA = 0x27
189+
};
190+
191+
enum LineParameterLocation : uint8_t
192+
{
193+
Energy = 0x01,
194+
EnergyUncertainty = 0x21,
195+
Abundance = 0x05,
196+
AbundanceUncertainty = 0x39,
197+
IsKeyLine = 0x1D,
198+
NuclideIndex = 0x1B,
199+
NoWeightMean = 0x1F,
200+
LineActivity = 0x0B,
201+
LineActivityUnceratinty = 0x13,
202+
LineEfficiency = 0x31,
203+
LineEfficiencyUncertainty = 0x35,
204+
LineMDA = 0x25,
205+
};
206+
207+
enum class EfficiencyModel : uint8_t
208+
{
209+
SPLINE, EMPIRICAL, AVERAGE, DUAL, LINEAR, Unknown, NotReadin
210+
};
211+
212+
//enum class FwhmType : uint8_t
213+
//{
214+
// CONSTANT, SQRT, Unknown, NotReadin
215+
//};
216+
217+
private:
218+
std::multimap<CAMBlock, uint32_t> blockAddresses;
219+
std::shared_ptr<std::vector<byte_type>> readData;
220+
std::vector<byte_type> writebytes;
221+
std::vector<std::vector<byte_type>> lines;
222+
std::vector<std::vector<byte_type>> nucs;
223+
std::vector<byte_type> specData;
224+
std::vector<Nuclide> writeNuclides;
225+
std::vector<Line> fileLines;
226+
std::vector<Nuclide> fileNuclides;
227+
std::vector<Peak> filePeaks;
228+
std::vector<uint32_t> fileSpectrum;
229+
std::vector<float> fileEneCal;
230+
231+
//FwhmType fwhmType;
232+
std::vector<float> fileShapeCal;
233+
234+
EfficiencyModel efficiencyModel; //Defaults to EfficiencyModel::Unknown;
235+
std::vector<EfficiencyPoint> efficiencyPoints;
236+
std::vector<Peak> peaks;
237+
238+
DetInfo det_info;
239+
uint32_t num_channels =0;
240+
241+
static constexpr uint16_t header_size = 0x800;
242+
static constexpr uint16_t block_header_size = 0x30;
243+
static constexpr uint8_t nuclide_line_size = 0x03;
244+
static constexpr size_t file_header_length = 0x800;
245+
static constexpr size_t sec_header_length = 0x30;
246+
static constexpr uint16_t acqp_rec_tab_loc = 0x01FB;
247+
248+
float key_line_intf_limit = 2.0; //keV
249+
bool sampBlock = false;
250+
bool specBlock = false;
251+
252+
public:
253+
CAMIO();
254+
void ReadFile(const std::vector<byte_type>& fileData);
255+
256+
// get data from a file
257+
std::vector<Line>& GetLines();
258+
std::vector<Nuclide>& GetNuclides();
259+
std::vector<Peak>& GetPeaks();
260+
std::vector<EfficiencyPoint>& GetEfficiencyPoints();
261+
/** Only valid after `GetEfficiencyPoints()` has been called (will be `EfficiencyModel::NotReadin` in this case) */
262+
EfficiencyModel GetEfficiencyModel() const;
263+
SpecUtils::time_point_t GetSampleTime();
264+
SpecUtils::time_point_t GetAquisitionTime();
265+
float GetLiveTime();
266+
float GetRealTime();
267+
std::vector<float>& GetShapeCalibration();
268+
std::vector<float>& GetEnergyCalibration();
269+
std::vector<uint32_t>& GetSpectrum();
270+
std::string GetSampleTitle();
271+
DetInfo& GetDetectorInfo();
272+
273+
// add data to CAMIO object for later file writing
274+
void AddNuclide(const std::string& name, const float halfLife,
275+
const float halfLifeUnc, const std::string& halfLifeUnit, const int nucNo = -1);
276+
void AddNuclide(const Nuclide& nuc);
277+
void AddLine(const float energy, const float enUnc, const float yield,
278+
const float yieldUnc, const int nucNo, const bool key = false);
279+
void AddLine(const Line& line);
280+
void AddLineAndNuclide(const float energy, const float yield, const std::string& name,
281+
const float halfLife, const std::string& halfLifeUnit, const bool noWeightMean = false,
282+
const float enUnc = -1, const float yieldUnc = -1, const float halfLifeUnc = -1 );
283+
void AddEnergyCalibration(const std::vector<float> coefficients);
284+
void AddDetectorType(const std::string& detector_type);
285+
void AddAcquitionTime(const SpecUtils::time_point_t& start_time);
286+
void AddRealTime(const float real_time);
287+
void AddLiveTime(const float live_time);
288+
void AddSampleTitle(const std::string& title);
289+
void AddGPSData(const double latitude, const double longitude,
290+
const float speed, const SpecUtils::time_point_t& position_time);
291+
void AddGPSData(const double latitude, const double longitude, const float speed);
292+
void AddSpectrum(const std::vector<uint32_t>& channel_counts);
293+
void AddSpectrum(const std::vector<float>& channel_counts);
294+
// create a file with the data added
295+
std::vector<byte_type>& CreateFile();
296+
297+
inline void SetKeyLineInerferenceLimit(const float limit) { key_line_intf_limit = limit; };
298+
float GetKeyLineInerferenceLimit() const { return key_line_intf_limit; }
299+
300+
protected:
301+
std::multimap<CAMBlock, uint32_t> ReadHeader();
302+
void ReadBlock(CAMBlock block);
303+
std::vector<uint8_t> GenerateBlock(CAMBlock block, size_t loc,
304+
const std::vector<std::vector<uint8_t>>& records = std::vector<std::vector<uint8_t>>(),
305+
uint16_t blockNo = 0, bool hasCommon = true);
306+
std::vector<uint8_t> GenerateBlockHeader(CAMBlock block, size_t loc, uint16_t numRec = 1,
307+
uint16_t numLines = 1, uint16_t blockNum = 0, bool hasCommon = false) const;
308+
uint16_t GetNumLines(const std::vector<uint8_t>& nuclRecord);
309+
std::vector<uint8_t> GenerateNuclide(const Nuclide nuc,
310+
const std::vector<uint16_t>& lineNums);
311+
std::vector<uint8_t> AddLinesToNuclide(const std::vector<uint8_t>& nuc,
312+
const std::vector<uint8_t>& lineNums);
313+
std::vector<uint8_t> GenerateLine(const Line line);
314+
void AssignKeyLines();
315+
316+
protected:
317+
// Add block reading function declarations
318+
void ReadGeometryBlock(size_t pos, uint16_t records);
319+
void ReadLinesBlock(size_t pos, uint16_t records);
320+
void ReadNuclidesBlock(size_t pos, uint16_t records);
321+
void ReadPeaksBlock(size_t pos, uint16_t records);
322+
323+
// Add GenerateFile declaration
324+
void GenerateFile(const std::vector<std::vector<uint8_t>>& blocks);
325+
326+
float ComputeUncertainty(float value);
327+
};
328+
329+
// Helper class for comparing lines
330+
class LineComparer {
331+
public:
332+
bool operator()(const std::vector<uint8_t>& x, const std::vector<uint8_t>& y) const;
333+
};
334+
335+
class NuclideComparer {
336+
public:
337+
bool operator()(const std::vector<uint8_t>& x, const std::vector<uint8_t>& y) const;
338+
};
339+
340+
} // namespace CAMInputOutput

0 commit comments

Comments
 (0)